Server that executes balanced DCA against a portfolio of cryptocurrency
This is not ready for use - it is in early development. If you want to see the state of the world, you can run docker-compose up -d --build
and visit localhost:8087
. Run docker-compose -f docker-compose-dev.yml -d
for development environment.
Distributed as a docker-compose file pulling down an app, a cron job runner, and a DB. The app will host the web front-end and handle setting and retrieving settings, as well as enabling or disabling the cron job scheduler. The scheduler will execute the job on-time and needs to be extremely crash resistant. The database needs to be able to store sensitive credentials securely.
The chron job, once enabled, executes automatic trades based on a variety of criteria, on a set interval.
- Scheduled once per interval
- If the cron job server crashes, when it is restarted it should check the interval and calculate the remaining time from the current time. If more than a single interval has passed, it should immediately execute and then schedule the next execution for the difference between the current time and the intended next interval time.
- Node script using setTimeout for scheduling
- PM2 to keep it alive in container
- Alpine docker image as base
- ??? for tests
- Bittrex node SDK for API requests
- Sequelize for ORM
- Configured by environment variables in the .env-chron file
- Query Bittrex for the current amount and price of each coin held on Bittrex (/getbalances)
- Query market cap data (coinmarketcap) for all interested coins
- For each coin:
- Query Bittrex for the current transaction fee, minimum order amount for USDT-coin pair (/getcurrencies)
- If 1 - (amount - tx fees) / amount <= fee tolerance, withdraw that coin to local address (/withdraw)
- Log withdrawal to transaction log
- Calculate investment amount for each coin (automatic: interval spend _ coin market cap / sum all market caps, manual: interval spend _ manual % allocation)
- Increment each coin's current spend amount
- Check if the coin has an outstanding order. If it does, cancel it
- Check if the coin buy is valid
-
than minimum transaction +/- some fuzzing
- some sanity check (what?) about ask price
- enough USDT in Bittrex to support it
-
- If valid, execute order with coins full spend amount (/buylimit)
- Poll until order has resolved (/getopenorders)
- Log buy to transaction log, set coin spend amount to 0
The database is a bog-standard pgsql database, pulled in from the common docker image.
- Postgres DB
- Just use standard pgsql image
- HMAC for storing API credentials?
- Configured by .env-db file
- Bittrex API credentials
- Local wallet address
- Remote wallet address
- Transaction log
- Requested interval and execution time
- Interval spend
- Current locally held coins
- Current coin spend amounts
- Fee tolerance for each coin
- Portfolio distribution
- Whether to manually or automatically distribute portfolio
The app contains a webserver for hosting the frontend, a little business logic for updating the DB with settings, and the migrations for the DB.
- Express server for serving frontend/assets
- Standard WebPack/TypeScript/React/Redux/SCSS stack for building frontend
- Sequelize for ORM/migrations
- Alpine docker image as base
- ChartJS or D3 for pretty graphs
- Configured by .env-app file
- Add Bittrex credentials
- View current local (logged - not actually inspecting blockchain) and remote holdings
- Set, update, and enable interval
- View transaction log
- Add local wallet address and fee tolerance
- Set and update portfolio distribution preference and actual distribution if manual
- Pretty graphs about portfolio performance?
- Transaction search
- Need to think about authorization - can only query your own data? Maybe create some roles?
- Only allowed access to own data for now, will worry about multi-tenant down the road
- Need to make tests more efficient - move unit/IT to their own block and do seeding/teardown separately so we're not running into all these weird DB states
- Add PortfolioDashboard container
- Add Settings container
- Add sorting to tables
- Add editing to table cells
- Handled through passport.js
- Just using Local strategy for now
- User context passed to resolvers
- Message handling TBD
- All objects should have UserID attached
- Prevent read/write unless userID matches
- Can be done in a resolver wrapper
As a user, I want to...
- be able to create an account
- be able to log in
- be able to add some coins to invest in
- set a fee tolerance
- set a percentage of the portfolio
- associate a local and remote wallet to the coin
- enable or disable a coin
- change wallets
- set my purchase amount
- set my purchase interval
- start or stop the purchases
- see my portfolio
- the amount of each coin on the exchange
- the amount of each coin that has been transferred locally
- the amount on each coin waiting to be spent
- see all transactions that have happened