Trade robot on Kraken Futures demo-platform.
Project tech-features:
- Clean Architecture design pattern
- Graceful Shutdown
- go-chi, Gorilla WebSocket, Postgres (pgx), logrus
- Integration with Telegram Bot
- REST API and Websocket API on Kraken Futures (demo) support
- Unit-tests coverage
❗️ Robot works with API of demo version of platform
❗️ Trading logic of the robot does not guarantee profitability
-
The robot uses stop-loss/take-profit strategy. User can configure robot by setting market, price and size. After robot is successfully started, it listens on 1-minute candles (via websocket subscription), compares the average candle price with user settings and sends ioc order on Kraken if the price is triggered.
-
The robot can be launched on several markets in parallel.
-
For conditions of robot start see /start or /startall endpoint.
-
Afer user configured inner robot order (/setsell or /setbuy) this order becomes active. If this order is trigged (sended to Kraken) or explicitly cancelled by the user (/unset...), it becomes inactive.
-
User can set a new order (e.g. set buy order if it was not set at startup), change the price and size in an already active one or cancel the order when the robot is already running on market (no need to stop the robot especially for that).
-
The robot sends notifications to Telegram bot (see notifications).
-
Information about executed orders is stored in Postgres.
Parameters must be set as environmental variables (you can use source setenv.sh
for convenience).
APIPublic - public API-key from Kraken demo-platform API Private - private API-key from Kraken demo-platform TgChatID - Telegram bot chat ID TgBotURL - https://api.telegram.org/bot[token]/sendMessage port - port on which the robot server will run dsn - string for connecting to Postgres
Use docker-compose.yaml
to start Postgres.
Some Makefile
rules:
make
- start robot servermake test
- run tests with coverage
✅ Start subscription on market: pi_ethusd
The robot is successfuly started on market.
⚠️ Stop subscription on market: pi_ethusd
The robot on market is stopped.
Reasons:
- It was explicitly stopped by user (/stop, /stopall).
- Websocket error (code 1006) and reconnection doesn't help.
- Server is stopped (graceful shutdown).
📌 Make buy order on pi_xbtusd. Price: 58620.50
Order was successfuly placed and executed.
❌ Fail to place order: pi_ethusd: sell: server error
Fail to send order to Kraken due to inner error.
❌ Fail to execute order: pi_xbtusd: sell: insufficient funds
Order was rejected because of balance error.
❌ Fail to execute order: pi_xbtusd: sell
Order was rejected because of every another reason except balance error.
POST /setmarket?market=`market`
Sets new market*.
Sample Response on Success:
JSON {"market":"pi_xbtusd", "status":"ok"}, Status 201 (Created)
POST /setsell?market=`market`&price=`price`&size=`size`
Sets inner sell order with passed query parameters. If no orders have been placed on this market before, then you must first set this market (/setmarket)*.
Sample Response on Success:
JSON {"market":"pi_xbtusd", "type":"sell", "price":4000, "size":1}, Status 201 (Created)
Sample Response on Fail:
JSON {"market":"pi_ethusd", "status":"No market was set: pi_ethusd"}, Status 400 (Bad Request)
POST /setbuy?market=`market`&price=`price`&size=`size`
Sets inner buy order with passed query parameters. If no orders have been placed on this market before, then you must first set this market (/setmarket)*.
Sample Response on Success:
JSON {"market":"pi_xbtusd", "type":"buy", "price":4000, "size":1}, Status 201 (Created)
Sample Response on Fail:
JSON {"market":"pi_ethusd", "status":"No market was set: pi_ethusd"}, Status 400 (Bad Request)
POST /unsetsell?market=`market`
Unsets inner sell order on market passed as parameter*.
Sample Response on Success:
JSON {"market":"pi_xbtusd", "status":"ok"}, Status 200 (OK)
Sample Response on Fail:
JSON {"market":"pi_ethusd", "status":"No market was set: pi_ethusd"}, Status 400 (Bad Request)
POST /unsetbuy?market=`market`
Unsets inner buy order on market passed as parameter*.
Sample Response on Success:
JSON {"market":"pi_xbtusd", "status":"ok"}, Status 200 (OK)
Sample Response on Fail:
JSON {"market":"pi_ethusd", "status":"No market was set: pi_ethusd"}, Status 400 (Bad Request)
POST /unsetall
Unsets all orders on all previously set markets.
JSON [{"market":"pi_xbtusd", "status":"ok"}, {"market":"pi_ethusd", "status":"ok"}], Status 200 (OK)
POST /start?market=`market`
Launches the robot on market passed as parameter. The market must be set before (/setmarket), there must be at least one active order on that market and the robot must not be already running on that market*.
Sample Response on Success:
JSON {"market":"pi_xbtusd", "status":"ok"}, Status 200 (OK)
Sample Response on Fail:
JSON {"market":"pi_ethusd", "status":"Fail to start, parameter wasn't set: market"}, Status 400 (Bad Request)
JSON {"market":"pi_ethusd", "status":"Fail to start, parameter wasn't set: pi_ethusd: orders"}, Status 400 (Bad Request)
JSON {"market":"pi_ethusd", "status":"Fail to start, subscription is already running: pi_ethusd"}, Status 400 (Bad Request)
JSON {"market":"pi_ethusd", "status":"Internal Server Error"}, Status 500 (Internal Server Error)
POST /startall
Launches the robot on all previously set markets. The launch criteria are the same as for /start. By the status field in the body of the response, you can understand which markets were launched and which were not and why.
JSON [{"market":"pi_xbtusd", "status":"ok"}, {"market":"pi_ethusd", "status":"Fail to start, parameter wasn't set: pi_ethusd: orders"}], Status 200 (OK)
POST /stop?market=`market`
Stops the robot on market passed as parameter*.
Sample Response on Success:
JSON {"market":"pi_xbtusd", "status":"ok"}, Status 200 (OK)
Sample Response on Fail:
JSON {"market":"pi_ethusd", "status":"No market was set: pi_ethusd"}, Status 400 (Bad Request)
POST /stopall
Stops the robot on all previously set markets.
JSON [{"market":"pi_xbtusd", "status":"ok"}, {"market":"pi_ethusd", "status":"ok"}], Status 200 (OK)
GET /active?market=`market`
Returns currently active orders on market passed as parameter*.
Sample Response on Success:
JSON [{"market":"pi_xbtusd", "type":"buy", "price":4000, "size":1}, {"market":"pi_xbtusd", "type":"sell", "price":4000, "size":1}], Status 200 (OK)
Sample Response on Fail:
JSON {"market":"pi_ethusd", "status":"No market was set: pi_ethusd"}, Status 400 (Bad Request)
GET /activeall
Returns all currently active orders on all previously set markets.
JSON [{"market":"pi_xbtusd", "type":"buy", "price":4000, "size":1}, {"market":"pi_ethusd", "type":"buy", "price":4000, "size":1}], Status 200 (OK)
GET /running
Returns markets where the robot is currently running.
JSON [{"market":"pi_xbtusd", "status":"running"}, {"market":"pi_ethusd", "running"}], Status 200 (OK)
GET /orders
Returns executed orders from the database.
Sample Response on Success:
JSON [{"time":"2021-12-01T13:37:37.278283Z", "market":"pi_xbtusd", "type":"buy", "price":56980.5, "size":1}], Status 200 (OK)
Sample Response on Fail:
text/plain Internal Server Error, Status 500 (Internal Server Error)
GET /accounts
Returns user balance info.
Sample Response on Success:
JSON [{"fi_xbtusd":"10"}, {"fi_ethusd":"0"}, ...], Status 200 (OK)
Sample Response on Fail:
text/plain Internal Server Error, Status 500 (Internal Server Error)
In all requests with query parameters the following responses may take place (text/plain):
Wrong query parameter: no [market/price/size]
, Status 400 (Bad Request)
No parameterWrong query parameter: [price/size]: [value]
, Status 400 (Bad Request)
Invalid parameter value (e.g. negative price)Internal Server Error
, Status 500 (Internal Server Error)
Internal error from the middleware during processing
For example, to start robot on pi_ethusd market you should:
- /setmarket?market=pi_ethusd
- /setsell?size=5&market=pi_ethusd&price=4000
- /start?market=pi_ethusd or /startall
- Profit!