[BOT] implement buy und sell propagating from worker to api
This commit is contained in:
parent
adbe4f30c8
commit
ed9ca77def
@ -16,6 +16,7 @@ import Transaction from "../../apiwrapper/transaction/Transaction.js";
|
|||||||
import TransactionUpdateEvent from "../../apiwrapper/event/TransactionUpdateEvent.js";
|
import TransactionUpdateEvent from "../../apiwrapper/event/TransactionUpdateEvent.js";
|
||||||
import TransactionFill from "../../apiwrapper/transaction/TransactionFill.js";
|
import TransactionFill from "../../apiwrapper/transaction/TransactionFill.js";
|
||||||
import TransactionStatus from "../../apiwrapper/transaction/TransactionStatus.js";
|
import TransactionStatus from "../../apiwrapper/transaction/TransactionStatus.js";
|
||||||
|
import TransactionPhase from "../../apiwrapper/transaction/TransactionPhase.js";
|
||||||
|
|
||||||
export default class BinanceApiClient extends APIClient {
|
export default class BinanceApiClient extends APIClient {
|
||||||
/**
|
/**
|
||||||
@ -266,6 +267,7 @@ export default class BinanceApiClient extends APIClient {
|
|||||||
"timestamp": Date.now()
|
"timestamp": Date.now()
|
||||||
}).then(resp => {
|
}).then(resp => {
|
||||||
transaction.buySettings.apiID = resp.orderId;
|
transaction.buySettings.apiID = resp.orderId;
|
||||||
|
transaction.phase = TransactionPhase.BUY_IN_PROGRESS;
|
||||||
}).catch(e => {
|
}).catch(e => {
|
||||||
this.getLogger().error("Unable to create buy order for " + transaction.id, {code: e.code, msg: e.message, url: e.requestUrl});
|
this.getLogger().error("Unable to create buy order for " + transaction.id, {code: e.code, msg: e.message, url: e.requestUrl});
|
||||||
const event = new TransactionUpdateEvent(transaction.id, transaction.buySettings.apiID, TransactionStatus.CANCELED)
|
const event = new TransactionUpdateEvent(transaction.id, transaction.buySettings.apiID, TransactionStatus.CANCELED)
|
||||||
@ -288,6 +290,7 @@ export default class BinanceApiClient extends APIClient {
|
|||||||
"timestamp": Date.now()
|
"timestamp": Date.now()
|
||||||
}).then(resp => {
|
}).then(resp => {
|
||||||
transaction.sellSettings.apiID = resp.orderId;
|
transaction.sellSettings.apiID = resp.orderId;
|
||||||
|
transaction.phase = TransactionPhase.SELL_IN_PROGRESS;
|
||||||
}).catch(e => {
|
}).catch(e => {
|
||||||
this.getLogger().error("Unable to create sell order for " + transaction.id, {code: e.code, msg: e.message, url: e.requestUrl});
|
this.getLogger().error("Unable to create sell order for " + transaction.id, {code: e.code, msg: e.message, url: e.requestUrl});
|
||||||
const event = new TransactionUpdateEvent(transaction.id, transaction.sellSettings.apiID, TransactionStatus.CANCELED)
|
const event = new TransactionUpdateEvent(transaction.id, transaction.sellSettings.apiID, TransactionStatus.CANCELED)
|
||||||
|
|||||||
@ -45,6 +45,10 @@ export default class Transaction extends Serializable {
|
|||||||
*/
|
*/
|
||||||
timestamp = 0;
|
timestamp = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {string} initiator
|
||||||
|
* @param {TradingPair} tradingPair
|
||||||
|
*/
|
||||||
constructor(initiator, tradingPair){
|
constructor(initiator, tradingPair){
|
||||||
super();
|
super();
|
||||||
this.initiator = initiator;
|
this.initiator = initiator;
|
||||||
|
|||||||
@ -123,7 +123,7 @@ export default class TradingBot {
|
|||||||
this.#loadWorker();
|
this.#loadWorker();
|
||||||
this.#worker.forEach(worker => {
|
this.#worker.forEach(worker => {
|
||||||
this.#registerTradingPair(worker.getTradingPair());
|
this.#registerTradingPair(worker.getTradingPair());
|
||||||
worker.init(this.#logger, this.#config.getDataDirectory());
|
worker.init(this.#logger, this.#config.getDataDirectory(), this);
|
||||||
});
|
});
|
||||||
this.#transactions.forEach(transaction => {
|
this.#transactions.forEach(transaction => {
|
||||||
const type = transaction.phase === (TransactionPhase.INITIAL || transaction.phase === TransactionPhase.BUY_IN_PROGRESS) ? "buy" : "sell";
|
const type = transaction.phase === (TransactionPhase.INITIAL || transaction.phase === TransactionPhase.BUY_IN_PROGRESS) ? "buy" : "sell";
|
||||||
@ -235,6 +235,7 @@ export default class TradingBot {
|
|||||||
handleAccountUpdate(accountUpdateEvent) {
|
handleAccountUpdate(accountUpdateEvent) {
|
||||||
switch (accountUpdateEvent.eventType) {
|
switch (accountUpdateEvent.eventType) {
|
||||||
case APIEventType.BALANCE_CHANGE:
|
case APIEventType.BALANCE_CHANGE:
|
||||||
|
this.#logger.info("Balance update: ", accountUpdateEvent);
|
||||||
// TODO update changed balances
|
// TODO update changed balances
|
||||||
break;
|
break;
|
||||||
case APIEventType.TRANSACTION_UPDATE:
|
case APIEventType.TRANSACTION_UPDATE:
|
||||||
@ -337,6 +338,41 @@ export default class TradingBot {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {AbstractWorker} worker
|
||||||
|
* @param {number} quantity
|
||||||
|
* @param {number} price
|
||||||
|
*/
|
||||||
|
requestBuy(worker, quantity, price){
|
||||||
|
if(this.#config.getUsdTradeLimit() / this.#config.getPerTradeLimit() >= this.#transactions.length){
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const transaction = new Transaction(worker.getId(), worker.getTradingPair());
|
||||||
|
transaction.buySettings.oderPrice = price;
|
||||||
|
transaction.buySettings.orderQuantity = Math.round(this.#config.getPerTradeLimit() / price);
|
||||||
|
this.#transactions.push(transaction);
|
||||||
|
this.#saveTransactions();
|
||||||
|
|
||||||
|
this.#api.requestBuy(transaction);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {AbstractWorker} worker
|
||||||
|
* @param {Transaction} transaction
|
||||||
|
*/
|
||||||
|
requestSell(worker, transaction){
|
||||||
|
this.#api.requestSell(transaction);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {AbstractWorker} worker
|
||||||
|
* @param {Transaction} transaction
|
||||||
|
*/
|
||||||
|
requestCancle(worker, transaction){
|
||||||
|
// not implemented as this class is only an interface!
|
||||||
|
}
|
||||||
|
|
||||||
#loadTransactions() {
|
#loadTransactions() {
|
||||||
try {
|
try {
|
||||||
this.#transactions = SerializableHelper.load(this.#config.getDataDirectory(), 'transactions.sjson', Transaction);
|
this.#transactions = SerializableHelper.load(this.#config.getDataDirectory(), 'transactions.sjson', Transaction);
|
||||||
@ -351,7 +387,7 @@ export default class TradingBot {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#saveTransactions() {
|
async #saveTransactions() {
|
||||||
SerializableHelper.save(this.#config.getDataDirectory(), 'transactions.sjson', this.#transactions);
|
SerializableHelper.save(this.#config.getDataDirectory(), 'transactions.sjson', this.#transactions);
|
||||||
SerializableHelper.save(this.#config.getDataDirectory(), 'transactionHistory.sjson', this.#transactionHistory);
|
SerializableHelper.save(this.#config.getDataDirectory(), 'transactionHistory.sjson', this.#transactionHistory);
|
||||||
}
|
}
|
||||||
@ -366,7 +402,7 @@ export default class TradingBot {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#saveWorker() {
|
async #saveWorker() {
|
||||||
const workerArr = [];
|
const workerArr = [];
|
||||||
Array.from(this.#worker.values()).forEach(w => workerArr.push(w));
|
Array.from(this.#worker.values()).forEach(w => workerArr.push(w));
|
||||||
SerializableHelper.save(this.#config.getDataDirectory(), 'worker.sjson', workerArr);
|
SerializableHelper.save(this.#config.getDataDirectory(), 'worker.sjson', workerArr);
|
||||||
|
|||||||
@ -5,6 +5,7 @@ import Serializable from "../../util/Serializable.js";
|
|||||||
import SerializableHelper from "../../util/SerializableHelper.js";
|
import SerializableHelper from "../../util/SerializableHelper.js";
|
||||||
import AssetData from "../data/asset/AssetData.js";
|
import AssetData from "../data/asset/AssetData.js";
|
||||||
import AbstractStrategy from "../strategy/AbstractStrategy.js";
|
import AbstractStrategy from "../strategy/AbstractStrategy.js";
|
||||||
|
import WorkerTradingApiProvider from "./WorkerTradingApiProvider.js";
|
||||||
|
|
||||||
export default class AbstractWorker extends Serializable {
|
export default class AbstractWorker extends Serializable {
|
||||||
|
|
||||||
@ -28,6 +29,11 @@ export default class AbstractWorker extends Serializable {
|
|||||||
*/
|
*/
|
||||||
#strategy = null;
|
#strategy = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @type {WorkerTradingApiProvider}
|
||||||
|
*/
|
||||||
|
#apiProvider = null
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @type {Logger}
|
* @type {Logger}
|
||||||
*/
|
*/
|
||||||
@ -49,9 +55,11 @@ export default class AbstractWorker extends Serializable {
|
|||||||
/**
|
/**
|
||||||
* @param {Logger} logger
|
* @param {Logger} logger
|
||||||
* @param {string} dataPath
|
* @param {string} dataPath
|
||||||
|
* @param {WorkerTradingApiProvider} apiProvider
|
||||||
*/
|
*/
|
||||||
init(logger, dataPath){
|
init(logger, dataPath, apiProvider){
|
||||||
this.#logger = logger;
|
this.#logger = logger;
|
||||||
|
this.#apiProvider = apiProvider;
|
||||||
if(this.#strategy != null){
|
if(this.#strategy != null){
|
||||||
this.#strategy.init(logger);
|
this.#strategy.init(logger);
|
||||||
}
|
}
|
||||||
@ -114,6 +122,13 @@ export default class AbstractWorker extends Serializable {
|
|||||||
return this.#logger;
|
return this.#logger;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @returns {WorkerTradingApiProvider}
|
||||||
|
*/
|
||||||
|
getApiProvider(){
|
||||||
|
return this.#apiProvider;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {string} dataPath path to data directory
|
* @param {string} dataPath path to data directory
|
||||||
*/
|
*/
|
||||||
|
|||||||
@ -28,16 +28,17 @@ export default class DefaultWorker extends AbstractWorker{
|
|||||||
*/
|
*/
|
||||||
onUpdate(assetData, transactions){
|
onUpdate(assetData, transactions){
|
||||||
this.getStrategy().updateAssetData(assetData);
|
this.getStrategy().updateAssetData(assetData);
|
||||||
|
const price = this.getStrategy().getAssetData().getOrderBook().getBestBid().price;
|
||||||
|
|
||||||
if(this.getStrategy().shouldBuy()){
|
if(this.getStrategy().shouldBuy()){
|
||||||
// TODO create transaction!
|
this.getApiProvider().requestBuy(this, Math.round(50 / price), price);
|
||||||
}
|
}
|
||||||
|
|
||||||
for(let transaction of transactions){
|
for(let transaction of transactions){
|
||||||
if(transaction.phase == TransactionPhase.BUY_DONE && this.getStrategy().shouldSell(transaction)){
|
if(transaction.phase == TransactionPhase.BUY_DONE && this.getStrategy().shouldSell(transaction)){
|
||||||
// TODO request sell!
|
this.getApiProvider().requestSell(this, transaction);
|
||||||
} else if(this.getStrategy().shouldCancle()){
|
} else if(this.getStrategy().shouldCancle()){
|
||||||
// TODO request cancle
|
this.getApiProvider().requestCancle(this, transaction);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
29
src/js/tradingbot/worker/WorkerTradingApiProvider.js
Normal file
29
src/js/tradingbot/worker/WorkerTradingApiProvider.js
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
import Transaction from "../../apiwrapper/transaction/Transaction.js";
|
||||||
|
import AbstractWorker from "./AbstractWorker.js";
|
||||||
|
|
||||||
|
export default class WorkerTradingApiProvider {
|
||||||
|
/**
|
||||||
|
* @param {AbstractWorker} worker
|
||||||
|
* @param {number} quantity
|
||||||
|
* @param {number} price
|
||||||
|
*/
|
||||||
|
requestBuy(worker, quantity, price){
|
||||||
|
// not implemented as this class is only an interface!
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {AbstractWorker} worker
|
||||||
|
* @param {Transaction} transaction
|
||||||
|
*/
|
||||||
|
requestSell(worker, transaction){
|
||||||
|
// not implemented as this class is only an interface!
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {AbstractWorker} worker
|
||||||
|
* @param {Transaction} transaction
|
||||||
|
*/
|
||||||
|
requestCancle(worker, transaction){
|
||||||
|
// not implemented as this class is only an interface!
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue
Block a user