Skip to content

Commit

Permalink
Updated features (#24)
Browse files Browse the repository at this point in the history
  • Loading branch information
chrisleekr authored Mar 6, 2021
1 parent 5db1f06 commit 88297fb
Show file tree
Hide file tree
Showing 51 changed files with 6,126 additions and 2,534 deletions.
3 changes: 2 additions & 1 deletion .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -34,9 +34,10 @@ jobs:
run: |
git config --global user.email "$GIT_CI_EMAIL"
git config --global user.name "$GIT_CI_NAME"
npm version patch -m "Update version to %s [skip ci]"
PACKAGE_VERSION=$(npm version patch -m "Update version to %s [skip ci]")
git status
git push https://$GIT_CI_USERNAME:$GIT_CI_PASSWORD@$GIT_REPO_DOMAIN/chrisleekr/binance-trading-bot.git HEAD:$GITHUB_REF
git push https://$GIT_CI_USERNAME:$GIT_CI_PASSWORD@$GIT_REPO_DOMAIN/chrisleekr/binance-trading-bot.git $PACKAGE_VERSION
- name: Build/Push production docker image
if:
github.repository == 'chrisleekr/binance-trading-bot' && github.ref ==
Expand Down
20 changes: 15 additions & 5 deletions .gitlab-ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,13 @@ bump-version-patch:
script:
- git config --global user.email "$GIT_CI_EMAIL"
- git config --global user.name "$GIT_CI_NAME"
- npm version patch -m "Update version to %s [skip ci]"
- git push https://$GIT_CI_USERNAME:$GIT_CI_PASSWORD@$GIT_REPO_DOMAIN/chrisleekr/binance-trading-bot.git HEAD:master
- PACKAGE_VERSION=$(npm version patch -m "Update version to %s [skip ci]")
- git push
https://$GIT_CI_USERNAME:$GIT_CI_PASSWORD@$GIT_REPO_DOMAIN/chrisleekr/binance-trading-bot.git
HEAD:master
- git push
https://$GIT_CI_USERNAME:$GIT_CI_PASSWORD@$GIT_REPO_DOMAIN/chrisleekr/binance-trading-bot.git
"$PACKAGE_VERSION"

production:
stage: build production
Expand All @@ -40,7 +45,12 @@ production:
- master
<<: *before-script
script:
- PACKAGE_VERSION=$(grep version package.json | cut -c 15- | rev | cut -c 3- | rev)
- docker build . --build-arg PACKAGE_VERSION=$PACKAGE_VERSION --build-arg NODE_ENV=production --target production-stage -t $REGISTRY_DOMAIN/chrisleekr/binance-trading-bot:latest -t $REGISTRY_DOMAIN/chrisleekr/binance-trading-bot:$PACKAGE_VERSION
- docker push $REGISTRY_DOMAIN/chrisleekr/binance-trading-bot:$PACKAGE_VERSION
- PACKAGE_VERSION=$(grep version package.json | cut -c 15- | rev | cut -c 3-
| rev)
- docker build . --build-arg PACKAGE_VERSION=$PACKAGE_VERSION --build-arg
NODE_ENV=production --target production-stage -t
$REGISTRY_DOMAIN/chrisleekr/binance-trading-bot:latest -t
$REGISTRY_DOMAIN/chrisleekr/binance-trading-bot:$PACKAGE_VERSION
- docker push
$REGISTRY_DOMAIN/chrisleekr/binance-trading-bot:$PACKAGE_VERSION
- docker push $REGISTRY_DOMAIN/chrisleekr/binance-trading-bot:latest
72 changes: 39 additions & 33 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,26 +10,25 @@ you can make money or not.**
**So use it at your own risk! I have no responsibility for any loss or hardship
incurred directly or indirectly by using this code.**

**Make sure you record last buy price in your note before you update any
changes.**
**Before update any changes, make sure record last buy price in the note. It may
lose the configuration or last buy price.**

## How it works

### Simple-Stop-Chaser
### Trading Bot

This method is buying at the lowest price without any indicator, never sell
under purchase price. And chase rising money. Stop chaser methodology was the
idea from [@d0x2f](https://github.com/d0x2f). I have found MACD indicators often
This bot is buying at the lowest price without any indicator, never sell under
purchase price. And chase rising money. Stop chaser methodology was the idea
from [@d0x2f](https://github.com/d0x2f). I have found MACD indicators often
mislead buying signal. In box pattern market, buy signal with the lowest price
is effective than using MACD indicators.

#### Note

- The bot can monitor multiple symbols.
- The bot can monitor multiple symbols. Each symbol will be monitored per
second.
- The bot is only tested and working with USDT pair in the FIAT market such as
BTCUSDT, ETHUSDT. You can add more FIAT symbols like BUSD, AUD using
`BINANCE_JOBS_SIMPLE_STOP_CHASER_SUPPORT_FIATS` or update from the frontend.
However, I didn't test in the live server. So use with your own risk.
BTCUSDT, ETHUSDT. You can add more FIAT symbols like BUSD, AUD from the
frontend. However, I didn't test in the live server. So use with your own
risk.
- The bot is using MongoDB to provide a persistence database. However, it does
not use the latest MongoDB to support Raspberry Pi 32bit. Used MongoDB version
is 3.2.20, which is provided by
Expand All @@ -47,6 +46,7 @@ is effective than using MACD indicators.
- It will only purchase the maximum purchase amount or less.
- It will not purchase if the base asset, such as BTC, has enough balance
to place a stop-loss limit order.
- If trading is disabled, then the bot won't place an order.
- If the current price is higher than the lowest closed price, then _do not
buy._

Expand All @@ -56,11 +56,22 @@ is effective than using MACD indicators.
- Get last buy price from the cache
- If the current price is higher than the minimum profit percentage _last
buy price_, then **place Stop-Loss-Limit order.**
- If trading is disabled, then the bot won't place an order.
- Otherwise, _do not place Stop-Loss-Limit order._
- If there is an opened Stop-Loss-Limit order, then check the current price.
- If the current price is higher than stop price, then cancel the open
order. Then it will place new Stop-Loss-Limit order in next process.

### Frontend + WebSocket

React.js based frontend communicating via Web Socket:

- List monitoring coins with buy/sell signals/open orders
- View account balances
- Manage global/symbol settings
- Delete caches that are not monitored
- Link to public URL

## Environment Parameters

Use environment parameters to adjust parameters. Check
Expand Down Expand Up @@ -92,43 +103,32 @@ Or use the frontend to adjust configurations after launching the application.
docker-compose up -d
```

or using the latest build image
or using the latest build image from DockerHub

```bash
docker-compose -f docker-compose.server.yml up -d
```

or if using Raspberry Pi 32bit
or if using Raspberry Pi 32bit. Must build again for Raspberry Pi.

```bash
docker build . --build-arg NODE_ENV=production --target production-stage -t chrisleekr/binance-trading-bot:latest
docker-compose -f docker-compose.rpi.yml up -d
```

[![asciicast](https://asciinema.org/a/371137.png)](https://asciinema.org/a/371137)

4. Open browser `http://0.0.0.0:8080` to see the frontend

- When launching the application, it will notify public URL to the Slack.

## Frontend + WebSocket
## Screenshots

React.js based frontend communicating via Web Socket:

- List monitoring coins with buy/sell signals/open orders
- View account balances
- Manage settings including symbols
- Delete caches that are not monitored
- Link to public URL

| Frontend Mobile | Setting |
| --------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------- |
| ![Screenshot1](https://user-images.githubusercontent.com/5715919/109266553-539c2b00-785c-11eb-9c2e-615ad922dd99.jpeg) | ![Screenshot2](https://user-images.githubusercontent.com/5715919/109266543-5139d100-785c-11eb-9076-b704178b3b1a.jpeg) |
| Frontend Mobile | Setting |
| -------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------- |
| ![Screenshot1](https://user-images.githubusercontent.com/5715919/110196331-ea3d9d00-7e97-11eb-8517-c3eaeb0f2698.png) | ![Screenshot2](https://user-images.githubusercontent.com/5715919/110196341-f7f32280-7e97-11eb-9aea-e645f678e185.png) |

| Frontend Desktop |
| ------------------------------------------------------------------------------------------------------------------- |
| ![Screenshot](https://user-images.githubusercontent.com/5715919/109266694-7cbcbb80-785c-11eb-862e-5afc83edbcfd.png) |

## Trades
| ![Screenshot](https://user-images.githubusercontent.com/5715919/110196322-d2feaf80-7e97-11eb-9ee0-a71e7a5c9ed7.png) |

### First trade

Expand All @@ -140,9 +140,9 @@ React.js based frontend communicating via Web Socket:

| Trade History | PNL Analysis |
| -------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------- |
| ![Screenshot3](https://user-images.githubusercontent.com/5715919/104917671-d4f3d880-59e7-11eb-87ea-b73a8e75f725.jpg) | ![Screenshot4](https://user-images.githubusercontent.com/5715919/104917674-d6250580-59e7-11eb-911f-9d5491fdfdcb.jpg) |
| ![Screenshot3](https://user-images.githubusercontent.com/5715919/110196375-38eb3700-7e98-11eb-870b-d2d145a6fb97.png) | ![Screenshot4](https://user-images.githubusercontent.com/5715919/110196380-41dc0880-7e98-11eb-98b7-697f5d2f351f.png) |

## Todo
## Changes & Todo

- [x] Support multiple symbols
- [x] Remove unused methods - Bollinger Bands, MACD Stop Chaser
Expand All @@ -162,6 +162,12 @@ React.js based frontend communicating via Web Socket:
buy price
- [x] Display estimated value in the frontend
- [x] Support other FIAT symbols such as BUSD, AUD
- [x] Allow entering more decimals for the last buy price
- [x] Override buy/sell configuration per symbol
- [x] Support PWA for frontend - now support "Add to Home screen"
- [x] Enable/Disable symbols trading, but continue to monitor
- [ ] Apply chase-stop-loss-limit order for buy signal as well
- [ ] Override the lowest value in the frontend
- [ ] Re-organise configuration structures
- [ ] Allow browser notification
- [ ] Secure frontend with the password
4 changes: 1 addition & 3 deletions app/helpers/__tests__/binance.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,7 @@ describe('binance', () => {
jest.clearAllMocks().resetModules();

jest.mock('binance-api-node', () => ({
default: jest.fn().mockImplementation(() => {
return { some: 'method' };
})
default: jest.fn().mockImplementation(() => ({ some: 'method' }))
}));
jest.mock('config');
config = require('config');
Expand Down
48 changes: 24 additions & 24 deletions app/helpers/__tests__/cache.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,11 @@ describe('cache', () => {

mockSet = jest.fn(() => true);
jest.mock('config');
jest.mock('ioredis', () => {
return jest.fn().mockImplementation(() => ({
jest.mock('ioredis', () =>
jest.fn().mockImplementation(() => ({
set: mockSet
}));
});
}))
);

cache = require('../cache');
});
Expand Down Expand Up @@ -59,11 +59,11 @@ describe('cache', () => {

mockGet = jest.fn(() => 'my-value');
jest.mock('config');
jest.mock('ioredis', () => {
return jest.fn().mockImplementation(() => ({
jest.mock('ioredis', () =>
jest.fn().mockImplementation(() => ({
get: mockGet
}));
});
}))
);

cache = require('../cache');

Expand All @@ -85,11 +85,11 @@ describe('cache', () => {

mockHSet = jest.fn(() => true);
jest.mock('config');
jest.mock('ioredis', () => {
return jest.fn().mockImplementation(() => ({
jest.mock('ioredis', () =>
jest.fn().mockImplementation(() => ({
hset: mockHSet
}));
});
}))
);

cache = require('../cache');
});
Expand All @@ -113,11 +113,11 @@ describe('cache', () => {

mockHGet = jest.fn(() => 'my-value');
jest.mock('config');
jest.mock('ioredis', () => {
return jest.fn().mockImplementation(() => ({
jest.mock('ioredis', () =>
jest.fn().mockImplementation(() => ({
hget: mockHGet
}));
});
}))
);

cache = require('../cache');

Expand All @@ -139,11 +139,11 @@ describe('cache', () => {

mockHGetAll = jest.fn(() => 'my-value');
jest.mock('config');
jest.mock('ioredis', () => {
return jest.fn().mockImplementation(() => ({
jest.mock('ioredis', () =>
jest.fn().mockImplementation(() => ({
hgetall: mockHGetAll
}));
});
}))
);

cache = require('../cache');

Expand All @@ -165,11 +165,11 @@ describe('cache', () => {

mockHDel = jest.fn(() => 'my-value');
jest.mock('config');
jest.mock('ioredis', () => {
return jest.fn().mockImplementation(() => ({
jest.mock('ioredis', () =>
jest.fn().mockImplementation(() => ({
hdel: mockHDel
}));
});
}))
);

cache = require('../cache');

Expand Down
20 changes: 5 additions & 15 deletions app/helpers/cache.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,7 @@ const set = async (key, value, ttl = undefined) => {
*
* @param {*} key
*/
const get = async key => {
return redis.get(key);
};
const get = async key => redis.get(key);

/**
* Set cache value
Expand All @@ -37,37 +35,29 @@ const get = async key => {
* @param {*} field
* @param {*} value
*/
const hset = async (key, field, value) => {
return redis.hset(key, field, value);
};
const hset = async (key, field, value) => redis.hset(key, field, value);

/**
* Get value from key
*
* @param {*} key
* @param {*} field
*/
const hget = async (key, field) => {
return redis.hget(key, field);
};
const hget = async (key, field) => redis.hget(key, field);

/**
* Get value from key
*
* @param {*} key
*/
const hgetall = async key => {
return redis.hgetall(key);
};
const hgetall = async key => redis.hgetall(key);

/**
* Delete key/field
*
* @param {*} key
* @param {*} field
*/
const hdel = async (key, field) => {
return redis.hdel(key, field);
};
const hdel = async (key, field) => redis.hdel(key, field);

module.exports = { set, get, hset, hget, hgetall, hdel };
7 changes: 7 additions & 0 deletions app/jobs/simpleStopChaser.js
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,13 @@ const execute = async logger => {
} else if (tradeActionResult.action === 'sell') {
symbolLogger.warn(`Got sell signal, but do nothing. Never lose money.`);
} else {
// Delete cached buy order result
cache.hdel(
'simple-stop-chaser-symbols',
`${symbol}-place-buy-order-result`
);

// Check stop loss limit order
orderResult = await helper.chaseStopLossLimitOrder(
symbolLogger,
indicators
Expand Down
Loading

0 comments on commit 88297fb

Please sign in to comment.