Commençons à écrire un bot de trading qui s'exécutera sur l'échange crypto de Binance. Le bot doit être capable de :
commercez par vous-même, générant une sorte de revenu
devrait être pratique pour créer et déployer diverses stratégies de trading
tester la stratégie sur des données historiques
Commençons par l'architecture
Nous avons un échange Binance qui a une API géniale. Par conséquent, l'architecture pourrait ressembler à ceci :

Appelez quelques méthodes "acheter moins cher" et "vendre plus cher". Mais la tâche pour nous est d'écrire un bot dans lequel un programmeur-trader conditionnel peut créer et tester de nouvelles stratégies de rentabilité. Par conséquent, il est nécessaire de séparer la logique commerciale de tout le reste. De plus, le module logique ne devrait pas se soucier de l'échange auquel il était connecté : à une API réelle ou à une pseudo-API (pour les tests). En tenant compte de tout cela, nous avons obtenu quelque chose comme cette architecture :

La base a été choisie par PostgreSQL. Il n'y a pas d'intention secrète ici. Vous pouvez utiliser n'importe lequel.
Du fait que chaque module mérite votre attention, tout cela ne rentrera pas dans un seul article. Par conséquent, je lance une mini-série : « Écrire un bot commercial de haute qualité en JS ». Par conséquent, abonnez-vous, installez-vous confortablement - commençons
Service pour les journaux
, log
error
. :
class LoggerService {
constructor(prefix) {
this.logPrefix = prefix
}
log(...props) {
console.log(new Date().toISOString().substr(0, 19), this.logPrefix, ...props)
}
error(...props) {
console.error(new Date().toISOString().substr(0, 19), this.logPrefix, ...props)
}
}
yarn add node-binance-api
BaseApiService. Binance SDK, LoggerService. Binance , . , futuresExchangeInfo()
. getAssetPricePrecision
getAssetQuantityPrecision
.
class BaseApiService {
constructor({ client, secret }) {
const { log, error } = new Logger('BaseApiService')
this.log = log
this.error = error
this.api = new NodeBinanceApi().options({
APIKEY: client,
APISECRET: secret,
hedgeMode: true,
})
this.exchangeInfo = {}
}
async init() {
try {
this.exchangeInfo = await this.api.futuresExchangeInfo()
} catch (e) {
this.error('init error', e)
}
}
getAssetQuantityPrecision(symbol) {
const { symbols = [] } = this.exchangeInfo
const s = symbols.find(s => s.symbol === symbol) || { quantityPrecision: 3 }
return s.quantityPrecision
}
getAssetPricePrecision(symbol) {
const { symbols = [] } = this.exchangeInfo
const s = symbols.find(s => s.symbol === symbol) || { pricePrecision: 2 }
return s.pricePrecision
}
}
, :
async futuresOrder(side, symbol, qty, price, params={}) {
try {
qty = Number(qty).toFixed(this.getAssetQuantityPrecision(symbol))
price = Number(price).toFixed(this.getAssetPricePrecision(symbol))
if (!params.type) {
params.type = ORDER.TYPE.MARKET
}
const res = await this.api.futuresOrder(side, symbol, qty, price || false, params)
this.log('futuresOrder', res)
return res
} catch (e) {
console.log('futuresOrder error', e)
}
}
. , . TradeService.
class TradeService {
constructor({client, secret}) {
const { log, error } = new LoggerService('TradeService')
this.log = log
this.error = error
this.api = new NodeBinanceApi().options({
APIKEY: client,
APISECRET: secret,
hedgeMode: true,
})
this.events = new EventEmitter()
}
marginCallCallback = (data) => this.log('marginCallCallback', data)
accountUpdateCallback = (data) => this.log('accountUpdateCallback', data)
orderUpdateCallback = (data) => this.emit(data)
subscribedCallback = (data) => this.log('subscribedCallback', data)
accountConfigUpdateCallback = (data) => this.log('accountConfigUpdateCallback', data)
startListening() {
this.api.websockets.userFutureData(
this.marginCallCallback,
this.accountUpdateCallback,
this.orderUpdateCallback,
this.subscribedCallback,
this.accountConfigUpdateCallback,
)
}
subscribe(cb) {
this.events.on('trade', cb)
}
emit = (data) => {
this.events.emit('trade', data)
}
}
SDK this.api.websockets.userFutureData
. this.orderUpdateCallback
. . EventEmitter
, , subscribe
.
? , . . /. . sequlize.
yarn add sequelize-cli -D
yarn add sequelize
npx sequelize-cli init
docker-compose.yml :
version: '3.1'
services:
db:
image: 'postgres:12'
restart: unless-stopped
volumes:
- ./volumes/postgresql/data:/var/lib/postgresql/data
environment:
POSTGRES_USER: root
POSTGRES_PASSWORD: example
POSTGRES_DB: bot
ports:
- 5432:5432
networks:
- postgres
networks:
postgres:
driver: bridge
. User
, Order
À suivre.
Dans le prochain article, nous écrirons un noyau qui reliera toutes ces pièces et fera le commerce du bot.