-
Notifications
You must be signed in to change notification settings - Fork 3
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit 1aa2491
Showing
11 changed files
with
6,260 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
{ | ||
"plugins": ["transform-runtime"], | ||
"presets": ["es2015", "stage-3"] | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
# top-most EditorConfig file | ||
root = true | ||
|
||
# Unix-style newlines with a newline ending every file | ||
[*] | ||
end_of_line = lf | ||
insert_final_newline = true | ||
indent_style = space | ||
indent_size = 2 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
# Logs | ||
logs | ||
*.log | ||
npm-debug.log* | ||
|
||
# Runtime data | ||
pids | ||
*.pid | ||
*.seed | ||
|
||
# Directory for instrumented libs generated by jscoverage/JSCover | ||
lib-cov | ||
|
||
# Coverage directory used by tools like istanbul | ||
coverage | ||
|
||
# nyc test coverage | ||
.nyc_output | ||
|
||
# Grunt intermediate storage (http:https://gruntjs.com/creating-plugins#storing-task-files) | ||
.grunt | ||
|
||
# node-waf configuration | ||
.lock-wscript | ||
|
||
# Compiled binary addons (http:https://nodejs.org/api/addons.html) | ||
build/Release | ||
|
||
# Dependency directories | ||
node_modules | ||
jspm_packages | ||
|
||
# Optional npm cache directory | ||
.npm | ||
|
||
# Optional REPL history | ||
.node_repl_history | ||
|
||
.webpack | ||
.serverless |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
MIT License | ||
|
||
Copyright (c) 2017 Anomaly Innovations | ||
|
||
Permission is hereby granted, free of charge, to any person obtaining a copy | ||
of this software and associated documentation files (the "Software"), to deal | ||
in the Software without restriction, including without limitation the rights | ||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
copies of the Software, and to permit persons to whom the Software is | ||
furnished to do so, subject to the following conditions: | ||
|
||
The above copyright notice and this permission notice shall be included in all | ||
copies or substantial portions of the Software. | ||
|
||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
SOFTWARE. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,107 @@ | ||
# Bitcoin trading dca - serverless | ||
|
||
Based upon the work of https://github.com/0x13a/bitcoin-trading-dca. | ||
|
||
This node script let you set a daily amount to invest on crypto currency (Bitcoin in this case) via the [kraken crypto exchange](https://kraken.com). | ||
|
||
Unfortunately aws lambda don't support node 8 yet so this project uses | ||
webpack to transpile your javascript and upload it to aws. | ||
|
||
### Dollar Cost Averaging | ||
|
||
> Dollar-cost averaging (DCA) is an investment technique of buying a fixed dollar amount of a particular investment on a regular schedule, regardless of the share price. The investor purchases more shares when prices are low and fewer shares when prices are high. | ||
Dollar Cost Averaging has being initially used in the stock market to pursue an investment on an higher number of stocks with the same amount spend, just by investing it in a longer period of time due to the volatility of the stocks. | ||
|
||
In the case of crypto-currency is well known that the volatility of those assets is way higher than the traditional shares purchased in the stock market. This makes the Dollar Cost Averaging strategy well suited for this type of investments. | ||
|
||
### How you should choose investment amount and range | ||
This highly depends on your risk level, in my case what I've done is set up a total investment amount. | ||
Let's say I want to invest 1000$ and I want to spread my investment for 3 months. I also know I want to invest daily to take advantage of the volatility of the bitcoin against the dollar. | ||
|
||
> 1000 / (3 * 30) = 1000 / 90 = ~11$ / day | ||
### Disclaimer | ||
|
||
Dollar Cost Averaging is meant to be used as a long-term strategy. This does not mean that returns are guaranteed, it's an investment and it's on your own risk. The general idea of this is to be used as [Buy, hold and don't watch too closely](https://www.cnbc.com/2016/03/04/warren-buffett-buy-hold-and-dont-watch-too-closely.html) | ||
|
||
### Requirements | ||
|
||
- [Install the Serverless Framework](https://serverless.com/framework/docs/providers/aws/guide/installation/) | ||
- [Configure your AWS CLI](https://serverless.com/framework/docs/providers/aws/guide/credentials/) | ||
- [Kraken API KEY](https://kraken.com) | ||
|
||
### Installation | ||
|
||
To create a new Serverless project with ES7 support. | ||
|
||
``` bash | ||
$ serverless install --url https://github.com/izifortune/bitcoin-trading-dca-serverless --name my-project | ||
``` | ||
|
||
Enter the new directory | ||
|
||
``` bash | ||
$ cd my-project | ||
``` | ||
|
||
Install the Node.js packages | ||
|
||
``` bash | ||
$ npm install | ||
``` | ||
|
||
### Configuration | ||
|
||
You will need to modify the `serverless.yml`: | ||
|
||
```yml | ||
custom: | ||
logsBucket: myBucketName | ||
logsFile: myLogFileHere | ||
``` | ||
|
||
`logsBucket` refer to the bucket name where do you want to log the transaction | ||
information. `logsFile` is the file name where to store the logs. | ||
|
||
```yml | ||
environment: | ||
KRAKEN_KEY=myKrakenKeyHere | ||
KRAKEN_SECRET=myKrakenSecretKeyHere | ||
INVESTMENT_AMOUNT=11.11 | ||
ASSETS_PAIR=XXBTZEUR | ||
``` | ||
|
||
Add all the info for kraken API as environment variables. | ||
|
||
### Schedule | ||
|
||
By default the schedule its setup through a cron job of aws lambda once | ||
a day. | ||
|
||
``` | ||
cron(0 10 * * ? *) | ||
``` | ||
|
||
You can modify this editing `serverless.yml`: | ||
|
||
```yml | ||
events: | ||
- schedule: cron(0 10 * * ? *) | ||
``` | ||
|
||
### Usage | ||
|
||
To run a function on your local | ||
|
||
``` bash | ||
$ serverless invoke local --function start | ||
``` | ||
|
||
Deploy your project | ||
|
||
``` bash | ||
$ serverless deploy | ||
``` | ||
|
||
To add another function as a new file to your project, simply add the new file and add the reference to `serverless.yml`. The `webpack.config.js` automatically handles functions in different files. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
// Add source map support for proper stack traces | ||
require('source-map-support').install(); | ||
|
||
// Catch all unhandled exceptions and print their stack trace. | ||
// Required if the handler function is async, as promises | ||
// can swallow error messages. | ||
process.on('unhandledRejection', function(e) { | ||
console.error(e.stack); | ||
process.exit(1); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,73 @@ | ||
const AWS = require('aws-sdk'); | ||
const Kraken = require('kraken-api'); | ||
|
||
const s3 = new AWS.S3(); | ||
const timestamp = () => new Date().toISOString(); | ||
// set an higher timeout | ||
const client = new Kraken(process.env.KRAKEN_KEY, process.env.KRAKEN_SECRET, { | ||
timeout: 60 * 60 * 48 * 1000 | ||
}); | ||
|
||
const investmentAmount = process.env.INVESTMENT_AMOUNT; | ||
// see full list of exhange pairs here | ||
// https://api.kraken.com/0/public/AssetPairs | ||
const pair = (process.env.ASSETS_PAIR || 'XXBTZEUR').toUpperCase(); | ||
|
||
const cryptoCurrency = pair.split('X')[1].slice(0, 3); | ||
const fiatCurrency = pair.split('Z')[1].slice(0, 3); | ||
|
||
const logging = async log => { | ||
try { | ||
const data = await s3.getObject({ | ||
Bucket: process.env.BUCKET, | ||
Key: process.env.LOG_FILE | ||
}).promise(); | ||
const body = data ? data.Body.toString('ascii') + '\n' : ''; | ||
await s3.putObject({ | ||
Bucket: process.env.BUCKET, | ||
Key: process.env.LOG_FILE, | ||
Body: body + log | ||
}).promise(); | ||
} catch (e) { | ||
console.error(e); | ||
} | ||
}; | ||
|
||
export const start = async (event, context, callback) => { | ||
try { | ||
// Retrieve crypto/eur price | ||
const tickResponse = await client.api('Ticker', {pair}); | ||
const cryptoPrice = tickResponse['result'][pair]['a'][0]; | ||
if (typeof cryptoPrice === 'undefined') { | ||
callback(null, { error: 'cryptoCurrency undefined' }) | ||
return; | ||
} | ||
const volumeToBuy = (investmentAmount/cryptoPrice).toFixed(6); | ||
const roundedInvestmentAmount = (volumeToBuy*cryptoPrice).toFixed(3); | ||
|
||
// Kraken does not allow to buy less than 0.002XBT | ||
if (volumeToBuy < 0.002) { | ||
callback(null, { error: 'Increase your investmentAmount' }) | ||
} | ||
const logMessage = `[${timestamp()}] Buying ${volumeToBuy} ${cryptoCurrency}` + | ||
` which is equal to ${roundedInvestmentAmount} ${fiatCurrency}` + | ||
` at price ${cryptoPrice} ${fiatCurrency}/${cryptoCurrency}\n`; | ||
// Log prices to file | ||
await logging(logMessage); | ||
// buy disposed amount for today | ||
const tradeResponse = await client.api('AddOrder', { | ||
pair, | ||
volume: volumeToBuy, | ||
type: 'buy', | ||
ordertype: 'market' | ||
}); | ||
// Retrieve and log transaction ids | ||
const txIds = tradeResponse['result']['txid']; | ||
if (typeof txIds === 'undefined') { | ||
callback(null, { error: 'Unable to read transaction ids' }); | ||
} | ||
callback(null, { message: txIds, event }); | ||
} catch (e) { | ||
callback(null, { error: e, event }); | ||
} | ||
} |
Oops, something went wrong.