Compare commits

...

2 Commits

12 changed files with 250 additions and 92 deletions

View File

@ -29,6 +29,11 @@ export default class BinanceApiClient extends APIClient {
*/
#restClient = null;
/**
* @type {Map<string, import("binance").SymbolExchangeInfo>}
*/
#assetPermissions = new Map();
/**
* @param {BinanceApiConfig} config
* @param {Logger} logger
@ -37,6 +42,7 @@ export default class BinanceApiClient extends APIClient {
super(config, logger);
this.#wsClient = new WebsocketClient(config.getWSClientConfig());
this.#restClient = new MainClient(config.getRestClientConfig());
this.#loadAssetInfo();
this.#wsClient.on('formattedMessage', this.#wsMessageHandler.bind(this));
this.#wsClient.on('open', this.#connectionOpened.bind(this));
this.#wsClient.on('reconnecting', this.#reconnected.bind(this));
@ -98,8 +104,8 @@ export default class BinanceApiClient extends APIClient {
}
const event = new TradeEvent(tradingPair);
event.price = data.price;
event.quantity = data.quantity;
event.price = parseFloat(data.price);
event.quantity = parseFloat(data.quantity);
this.dispatchAssetEvent(event);
}
@ -115,12 +121,12 @@ export default class BinanceApiClient extends APIClient {
const event = new OrderBookUpdateEvent(tradingPair);
event.updateId = data.lastUpdateId;
if(data.bids && data.asks){
data.bids.forEach(b => event.bids.push(new OrderBookEntry(b[0], b[1])));
data.asks.forEach(a => event.asks.push(new OrderBookEntry(a[0], a[1])));
data.bids.forEach(b => event.bids.push(new OrderBookEntry(parseFloat(b[0]), parseFloat(b[1]))));
data.asks.forEach(a => event.asks.push(new OrderBookEntry(parseFloat(a[0]), parseFloat(a[1]))));
event.isReset = true;
} else {
data.bidDepthDelta.forEach(b => event.bids.push(new OrderBookEntry(b.price, b.quantity)));
data.askDepthDelta .forEach(a => event.asks.push(new OrderBookEntry(a.price, a.quantity)));
data.bidDepthDelta.forEach(b => event.bids.push(new OrderBookEntry(parseFloat(b.price), parseFloat(b.quantity))));
data.askDepthDelta .forEach(a => event.asks.push(new OrderBookEntry(parseFloat(a.price), parseFloat(a.quantity))));
}
@ -136,16 +142,16 @@ export default class BinanceApiClient extends APIClient {
}
const event = new Ticker24hEvent(tradingPair);
event.priceChange = data.priceChange;
event.priceChangePercent = data.priceChangePercent;
event.weightedAveragePrice = data.weightedAveragePrice;
event.bestBidPrice = data.bestBid;
event.bestBidQuantity = data.bestBidQuantity;
event.bestAskPrice = data.bestAskPrice;
event.bestAskQuantity = data.bestAskQuantity;
event.high = data.high;
event.low = data.low;
event.trades = data.trades;
event.priceChange = parseFloat(data.priceChange);
event.priceChangePercent = parseFloat(data.priceChangePercent);
event.weightedAveragePrice = parseFloat(data.weightedAveragePrice);
event.bestBidPrice = parseFloat(data.bestBid);
event.bestBidQuantity = parseFloat(data.bestBidQuantity);
event.bestAskPrice = parseFloat(data.bestAskPrice);
event.bestAskQuantity = parseFloat(data.bestAskQuantity);
event.high = parseFloat(data.high);
event.low = parseFloat(data.low);
event.trades = parseFloat(data.trades);
this.dispatchAssetEvent(event);
}
@ -158,10 +164,10 @@ export default class BinanceApiClient extends APIClient {
return;
}
const event = new KLineEvent(tradingPair, data.kline.high, data.kline.low, data.kline.open, data.kline.close);
const event = new KLineEvent(tradingPair, parseFloat(data.kline.high), parseFloat(data.kline.low), parseFloat(data.kline.open), parseFloat(data.kline.close));
event.isClosed = data.kline.final;
event.startTime = data.kline.startTime;
event.endTime = data.kline.endTime;
event.startTime = parseFloat(data.kline.startTime);
event.endTime = parseFloat(data.kline.endTime);
this.dispatchAssetEvent(event);
}
@ -172,7 +178,7 @@ export default class BinanceApiClient extends APIClient {
async #fireAccountBalanceChangeEvent(data) {
const event = new BalanceChangeEvent();
data.balances.forEach(balanceUpdate => {
event.setChangedBalance(balanceUpdate.asset, balanceUpdate.availableBalance);
event.setChangedBalance(balanceUpdate.asset, parseFloat(balanceUpdate.availableBalance));
});
this.dispatchAccountEvent(event);
@ -234,7 +240,7 @@ export default class BinanceApiClient extends APIClient {
const event = new BalanceChangeEvent();
resp.forEach(coinInfo => {
if (coinInfo.free > 0) {
event.setChangedBalance(coinInfo.coin, coinInfo.free);
event.setChangedBalance(coinInfo.coin, parseFloat(coinInfo.free));
}
});
@ -260,17 +266,18 @@ export default class BinanceApiClient extends APIClient {
"symbol": transaction.symbol.getKey(),
"side": "BUY",
"type": "LIMIT",
"price": transaction.buySettings.orderPrice,
"quantity" : transaction.buySettings.orderQuantity,
"price": this.#correctPriceForAsset(transaction.buySettings.orderPrice, transaction.symbol.getKey()),
"quantity": this.#correctQuantityForAsset(transaction.buySettings.orderQuantity, transaction.symbol.getKey()),
"newClientOrderId": transaction.id,
"timeInForce": "GTC",
"timestamp": Date.now()
}).then(resp => {
transaction.buySettings.apiID = resp.orderId;
transaction.phase = TransactionPhase.BUY_IN_PROGRESS;
transaction.lockedForUpdate = false;
}).catch(e => {
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);
this.dispatchAccountEvent(event);
});
}
@ -283,17 +290,18 @@ export default class BinanceApiClient extends APIClient {
"symbol": transaction.symbol.getKey(),
"side": "SELL",
"type": "LIMIT",
"price": transaction.sellSettings.orderPrice,
"quantity" : transaction.sellSettings.orderQuantity,
"price": this.#correctPriceForAsset(transaction.sellSettings.orderPrice, transaction.symbol.getKey()),
"quantity" : this.#correctQuantityForAsset(transaction.sellSettings.orderQuantity, transaction.symbol.getKey()),
"newClientOrderId": transaction.id,
"timeInForce": "GTC",
"timestamp": Date.now()
}).then(resp => {
transaction.sellSettings.apiID = resp.orderId;
transaction.phase = TransactionPhase.SELL_IN_PROGRESS;
transaction.lockedForUpdate = false;
}).catch(e => {
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);
this.dispatchAccountEvent(event);
});
}
@ -302,29 +310,41 @@ export default class BinanceApiClient extends APIClient {
* @param {Transaction} transaction
*/
requestBuyCancel(transaction){
this.#restClient.cancelOrder({
"symbol": transaction.symbol.getKey(),
"orderId": transaction.buySettings.apiID,
"origClientOrderId": transaction.id
}).then(resp =>{
this.requestTransactionUpdate(transaction, "buy");
}).catch(e => {
this.getLogger().error("Unable to cancle buy order for " + transaction.id, {code: e.code, msg: e.message, url: e.requestUrl});
});
this.#requestCancel(transaction.buySettings.apiID, transaction.id, transaction.symbol.getKey());
}
/**
* @param {Transaction} transaction
*/
requestSellCancel(transaction){
this.#restClient.cancelOrder({
"symbol": transaction.symbol.getKey(),
"orderId": transaction.sellSettings.apiID,
"origClientOrderId": transaction.id
}).then(resp =>{
this.requestTransactionUpdate(transaction, "sell");
this.#requestCancel(transaction.sellSettings.apiID, transaction.id, transaction.symbol.getKey());
}
/**
* @param {string} orderId
* @param {string} clientId
* @param {string} symbol
*/
#requestCancel(orderId, clientId, symbol){
/**
* @type {import("binance").CancelOrderParams}
*/
const orderParams = {
"symbol": symbol,
};
if(clientId != null && clientId != ""){
orderParams.origClientOrderId = clientId;
}
if(orderId != null && orderId != ""){
orderParams.orderId = orderId;
}
this.#restClient.cancelOrder(orderParams).then(resp =>{
this.#requestOrderUpdate(orderId, clientId, symbol);
}).catch(e => {
this.getLogger().error("Unable to cancle sell order for " + transaction.id, {code: e.code, msg: e.message, url: e.requestUrl});
this.getLogger().error("Unable to cancle order for " + clientId, {code: e.code, msg: e.message, url: e.requestUrl});
});
}
@ -343,13 +363,28 @@ export default class BinanceApiClient extends APIClient {
* @param {string} symbol
*/
#requestOrderUpdate(orderId, clientId, symbol){
this.#restClient.getOrder({
/**
* @type {import("binance").GetOrderParams}
*/
const orderParams = {
"symbol": symbol,
"orderId": orderId,
"origClientOrderId": clientId,
}).then(resp => {
};
if(clientId != null && clientId != ""){
orderParams.origClientOrderId = clientId;
}
if(orderId != null && orderId != ""){
orderParams.orderId = orderId;
}
this.#restClient.getOrder(orderParams).then(resp => {
const event = new TransactionUpdateEvent(resp.clientOrderId, resp.orderId, resp.status, resp.updateTime);
this.#requestTransactionFills(orderId, clientId, symbol, event);
if(resp.status == "CANCELED" && parseFloat(resp.executedQty) <= 0){
this.dispatchAccountEvent(event);
} else {
this.#requestTransactionFills(orderId, clientId, symbol, event);
}
}).catch(e => {
this.getLogger().error("Unable to get order status for " + clientId + "(" + orderId + ")", {code: e.code, msg: e.message, url: e.requestUrl});
});
@ -366,10 +401,69 @@ export default class BinanceApiClient extends APIClient {
"symbol": symbol,
"orderId": orderId,
}).then(resp => {
resp.forEach(trade => event.fills.push(new TransactionFill(trade.price, trade.qty)));
resp.forEach(trade => event.fills.push(new TransactionFill(parseFloat(trade.price), parseFloat(trade.qty))));
this.dispatchAccountEvent(event);
}).catch(e => {
this.getLogger().error("Unable to get order fills for " + clientId + "(" + orderId + ")", {code: e.code, msg: e.message, url: e.requestUrl});
});
}
#loadAssetInfo(){
this.#restClient.getExchangeInfo().then(exchangeInfo => {
exchangeInfo.symbols.forEach(symbolInfo => {
this.#assetPermissions.set(symbolInfo.symbol, symbolInfo);
});
}).catch(e => {
this.getLogger().error("Unable to get exchange info!");
});
}
/**
* @param {number} price
* @param {string} asset
* @returns {number}
*/
#correctPriceForAsset(price, asset){
if(!this.#assetPermissions.has(asset)){
return price;
}
const symbolInfo = this.#assetPermissions.get(asset);
const priceFilter = symbolInfo.filters.find(filter => filter.filterType == 'PRICE_FILTER');
let newPrice = parseFloat(price);
if(priceFilter != null){
newPrice = this.#toPrecision(newPrice, priceFilter.tickSize);
}
return newPrice;
}
/**
* @param {number} quantity
* @param {string} asset
* @returns {number}
*/
#correctQuantityForAsset(quantity, asset){
if(!this.#assetPermissions.has(asset)){
return quantity;
}
const symbolInfo = this.#assetPermissions.get(asset);
const lotFilter = symbolInfo.filters.find(filter => filter.filterType == 'LOT_SIZE');
let newQuantity = parseFloat(quantity);
if(lotFilter != null){
newQuantity = this.#toPrecision(newQuantity, lotFilter.stepSize);
}
return newQuantity;
}
#toPrecision(value, precision){
let precisionDigits = Math.log(Math.round(1/parseFloat(precision))) * Math.LOG10E + 1 | 0;
precisionDigits = precisionDigits > 0 && precision >= 1 ? precisionDigits - 1 : precisionDigits;
return parseFloat(value).toFixed(precisionDigits);
}
}

View File

@ -39,7 +39,7 @@ export default class TransactionUpdateEvent extends APIEvent{
super(APIEventType.TRANSACTION_UPDATE);
this.apiId = apiId;
this.transactionId = transactionId;
this.statis = status;
this.status = status;
this.timestamp = timestamp;
}
}

View File

@ -45,6 +45,11 @@ export default class Transaction extends Serializable {
*/
timestamp = 0;
/**
* @type {boolean} indicates, that the transaction was locked for sell/buy/update and will be unlocked, when the action is over
*/
lockedForUpdate = false;
/**
* @param {string} initiator
* @param {TradingPair} tradingPair
@ -70,6 +75,7 @@ export default class Transaction extends Serializable {
obj.id = this.id;
obj.result = this.result;
obj.phase = this.phase;
obj.timestamp = this.timestamp;
obj.symbol = SerializableHelper.serialize(this.symbol);
obj.buySettings = SerializableHelper.serialize(this.buySettings);
obj.sellSettings = SerializableHelper.serialize(this.sellSettings);
@ -89,6 +95,7 @@ export default class Transaction extends Serializable {
obj.id = tmpObj.id;
obj.result = tmpObj.result;
obj.phase = tmpObj.phase;
obj.timestamp = tmpObj.timestamp;
obj.symbol = SerializableHelper.deserialize(tmpObj.symbol);
obj.buySettings = SerializableHelper.deserialize(tmpObj.buySettings);
obj.sellSettings = SerializableHelper.deserialize(tmpObj.sellSettings);

View File

@ -129,7 +129,7 @@ export default class TransactionPhase {
return phase;
}
if(this.isBuyPhase(currentPhase)){
if(TransactionPhase.INITIAL == currentPhase || TransactionPhase.BUY_IN_PROGRESS == currentPhase){
if(TransactionStatus.isCancled(status) && !hasFills){
return this.CANCELED;
}
@ -137,9 +137,7 @@ export default class TransactionPhase {
if((TransactionStatus.FILLED == status) || (TransactionStatus.isCancled(status) && hasFills)){
return this.BUY_DONE;
}
}
if(this.isSellPhase(currentPhase)){
} else if (TransactionPhase.BUY_DONE == currentPhase || TransactionPhase.SELL_IN_PROGRESS == currentPhase){
if(TransactionStatus.isCancled(status)){
return this.BUY_DONE;
}
@ -147,8 +145,10 @@ export default class TransactionPhase {
if(TransactionStatus.FILLED == status){
return this.FINISHED;
}
} else if (TransactionPhase.SELL_DONE == currentPhase){
return this.FINISHED;
}
return phase;
return currentPhase;
}
}

View File

@ -34,6 +34,24 @@ try{
console.log(e);
}
/*const logger = new Logger("C:/Users/Wlad/Projekte/BinanceBot/binance_bot/data/log");
const api = new BinanceApiClient(BinanceApiConfig.createTestNetConfig(), logger);
const listener = {
handleAssetUpdate: function(accountUpdateEvent){
//;
},
handleAccountUpdate: function(accountUpdateEvent){
console.log(accountUpdateEvent);
}
};
api.registerAccountEventListener(listener);
api.registerAssetEventListener(listener);
const transaction = new Transaction("test", TradingPairs.GALAUSDT);
transaction.buySettings = new TransactionSettings(0.0343, 874.89064);
setTimeout(() => {api.requestBuy(transaction);}, 5000);*/

View File

@ -45,7 +45,7 @@ export default class Logger {
return new winston.transports.DailyRotateFile({
filename: 'application-%DATE%.log',
dirname: logPath,
datePattern: 'YYYY-MM-DD-HH',
datePattern: 'YYYY-MM-DD',
zippedArchive: true,
maxSize: '10m',
maxFiles: '7d'
@ -60,7 +60,7 @@ export default class Logger {
return new winston.transports.DailyRotateFile({
filename: 'error-%DATE%.log',
dirname: logPath,
datePattern: 'YYYY-MM-DD-HH',
datePattern: 'YYYY-MM-DD',
zippedArchive: true,
maxSize: '20m',
maxFiles: '7d',

View File

@ -126,8 +126,11 @@ export default class TradingBot {
worker.init(this.#logger, this.#config.getDataDirectory(), this);
});
this.#transactions.forEach(transaction => {
const type = transaction.phase === (TransactionPhase.INITIAL || transaction.phase === TransactionPhase.BUY_IN_PROGRESS) ? "buy" : "sell";
this.#api.requestTransactionUpdate(transaction, type);
if(transaction.buySettings != null && (transaction.phase === TransactionPhase.INITIAL || transaction.phase === TransactionPhase.BUY_IN_PROGRESS)){
this.#api.requestTransactionUpdate(transaction, 'buy');
} else if(transaction.sellSettings != null){
this.#api.requestTransactionUpdate(transaction, 'sell');
}
});
this.#startTime = Date.now();
@ -235,8 +238,7 @@ export default class TradingBot {
handleAccountUpdate(accountUpdateEvent) {
switch (accountUpdateEvent.eventType) {
case APIEventType.BALANCE_CHANGE:
this.#logger.info("Balance update: ", accountUpdateEvent);
// TODO update changed balances
this.#accountInfo.updateBalances(accountUpdateEvent);
break;
case APIEventType.TRANSACTION_UPDATE:
this.#updateTransaction(accountUpdateEvent);
@ -282,7 +284,10 @@ export default class TradingBot {
let index = -1;
this.#transactions.forEach((v, i) => {
if (v.id == event.transactionId || v.buySettings.apiID == event.apiId || v.sellSettings.apiID == event.apiId) {
if (v.id == event.transactionId
|| (v.buySettings != null && v.buySettings.apiID == event.apiId)
|| (v.sellSettings != null && v.sellSettings.apiID == event.apiId)
) {
transaction = v;
index = i;
}
@ -299,14 +304,17 @@ export default class TradingBot {
this.#calculateTradeValues(transaction.buySettings, event.fills);
} else if (TransactionPhase.isFinalPhase(nextTransactionPhase)) {
this.#calculateTradeValues(transaction.sellSettings, event.fills);
transaction.result = (sellSettings.quantity * sellSettings.price) - (buySettings.quantity * buySettings.price)
transaction.result = (transaction.sellSettings.quantity * transaction.sellSettings.price) - (transaction.buySettings.quantity * transaction.buySettings.price)
this.#transactionHistory.push(transaction);
this.#transactions.splice(index, 1);
}
transaction.phase = nextTransactionPhase;
transaction.lockedForUpdate = false;
this.#saveTransactions();
}
transaction.lockedForUpdate = false;
}
/**
@ -323,7 +331,7 @@ export default class TradingBot {
});
taSettings.quantity = quantity;
taSettings.price = priceSum / quantity;
taSettings.price = quantity != 0 ? priceSum / quantity : 0;
}
/**
@ -349,8 +357,8 @@ export default class TradingBot {
}
const transaction = new Transaction(worker.getId(), worker.getTradingPair());
transaction.buySettings.orderPrice = price;
transaction.buySettings.orderQuantity = Math.round(this.#config.getPerTradeLimit() / price);
transaction.buySettings = new TransactionSettings(price, this.#config.getPerTradeLimit() / price);
transaction.lockedForUpdate = true;
this.#transactions.push(transaction);
this.#saveTransactions();
@ -360,8 +368,15 @@ export default class TradingBot {
/**
* @param {AbstractWorker} worker
* @param {Transaction} transaction
* @param {number} price
*/
requestSell(worker, transaction){
requestSell(worker, transaction, price){
if(transaction.lockedForUpdate){
this.#logger.warn("Attempt to sell a locked transaction!", transaction.id);
return;
}
transaction.lockedForUpdate = true;
transaction.sellSettings = new TransactionSettings(price, parseFloat(transaction.buySettings.quantity));
this.#api.requestSell(transaction);
}
@ -370,12 +385,26 @@ export default class TradingBot {
* @param {Transaction} transaction
*/
requestCancle(worker, transaction){
// not implemented as this class is only an interface!
if(transaction.lockedForUpdate){
this.#logger.warn("Attempt to cancel a locked transaction!", transaction.id);
return;
}
if(transaction.buySettings != null && transaction.phase == TransactionPhase.BUY_IN_PROGRESS){
transaction.lockedForUpdate = true;
this.#api.requestBuyCancel(transaction);
}
if(transaction.sellSettings != null && transaction.phase == TransactionPhase.SELL_IN_PROGRESS){
transaction.lockedForUpdate = true;
this.#api.requestSellCancel(transaction);
}
}
#loadTransactions() {
try {
this.#transactions = SerializableHelper.load(this.#config.getDataDirectory(), 'transactions.sjson', Transaction);
this.#transactions = this.#transactions.filter(t => t.phase != TransactionPhase.INITIAL);
this.#transactions.forEach(t => t.lockedForUpdate = false);
} catch (e) {
this.#logger.warn("Bot was unable to load any transactions. Assuming no active transactions existing!", e);
}

View File

@ -1,3 +1,4 @@
import BalanceChangeEvent from "../../../apiwrapper/event/BalanceChangeEvent.js";
import AccountRights from "./AccountRights.js";
import AccountStatus from "./AccountStatus.js";
@ -23,9 +24,14 @@ export default class AccountInfo {
*/
#balances = new Map();
/**
* @type {number}
*/
#lastBalanceUpdate = 0;
constructor() {
//super();
this.#updateTime = Date.now();
this.#lastBalanceUpdate = Date.now();
}
/**
@ -84,23 +90,19 @@ export default class AccountInfo {
}
/**
* @param {AccountInformation} accountInfo
* @param {BalanceChangeEvent} balanceEvent
*/
update(accountInfo) {
// TODO
/*if (accountInfo == null) {
updateBalances(balanceEvent){
if(balanceEvent.timestamp < this.#lastBalanceUpdate){
return;
}
this.#updateTime = accountInfo.updateTime;
this.#canDeposit = accountInfo.canDeposit;
this.#canTrade = accountInfo.canTrade;
this.#canWithdraw = accountInfo.canWithdraw;
for (let balance of accountInfo.balances) {
if (balance.free > 0) {
this.#balances.set(balance.asset, balance.free);
balanceEvent.changedBalances.forEach((balance, symbol) => {
if(balance > 0 || this.#balances.has(symbol)){
this.#balances.set(symbol, balance);
}
}*/
});
this.#lastBalanceUpdate = balanceEvent.timestamp;
}
}

View File

@ -1,4 +1,5 @@
import Transaction from "../../apiwrapper/transaction/Transaction.js";
import TransactionPhase from "../../apiwrapper/transaction/TransactionPhase.js";
import AbstractStrategy from "./AbstractStrategy.js";
export default class AvgMinMaxStrategy extends AbstractStrategy {
@ -52,6 +53,12 @@ export default class AvgMinMaxStrategy extends AbstractStrategy {
* @returns {boolean}
*/
shouldCancle(transaction) {
const price = this.getAssetData().getOrderBook().getBestBid().price;
if(transaction.buySettings != null && transaction.phase == TransactionPhase.BUY_IN_PROGRESS){
return transaction.buySettings.orderPrice * 1.002 < price;
}
return false;
}

View File

@ -28,7 +28,7 @@ export default class DefaultWorker extends AbstractWorker{
*/
onUpdate(assetData, transactions){
this.getStrategy().setAssetData(assetData);
const price = this.getStrategy().getAssetData().getOrderBook().getBestBid().price;
const price = parseFloat(this.getStrategy().getAssetData().getOrderBook().getBestBid().price);
if(this.getStrategy().shouldBuy()){
this.getApiProvider().requestBuy(this, Math.round(50 / price), price);
@ -36,8 +36,8 @@ export default class DefaultWorker extends AbstractWorker{
for(let transaction of transactions){
if(transaction.phase == TransactionPhase.BUY_DONE && this.getStrategy().shouldSell(transaction)){
this.getApiProvider().requestSell(this, transaction);
} else if(this.getStrategy().shouldCancle()){
this.getApiProvider().requestSell(this, transaction, price);
} else if(this.getStrategy().shouldCancle(transaction)){
this.getApiProvider().requestCancle(this, transaction);
}
}

View File

@ -11,11 +11,12 @@ export default class WorkerTradingApiProvider {
// not implemented as this class is only an interface!
}
/**
/**
* @param {AbstractWorker} worker
* @param {Transaction} transaction
* @param {number} price
*/
requestSell(worker, transaction){
requestSell(worker, transaction, price){
// not implemented as this class is only an interface!
}

View File

@ -24,8 +24,8 @@ export default class TransactionConverter extends AbstractConverter {
phase: obj.phase,
timestamp:obj.timestamp,
result: obj.result,
buySettings: tsConverter.toRestObject(obj.buySettings),
sellSettings: tsConverter.toRestObject(obj.sellSettings),
buySettings: obj.buySettings == null ? null : tsConverter.toRestObject(obj.buySettings),
sellSettings: obj.sellSettings == null ? null : tsConverter.toRestObject(obj.sellSettings),
symbol: obj.symbol.getKey()
};
}
@ -43,8 +43,8 @@ export default class TransactionConverter extends AbstractConverter {
t.phase = obj.phase;
t.timestamp = obj.timestamp;
t.result = obj.result;
t.buySettings = tsConverter.fromRestObject(obj.buySettings);
t.sellSettings = tsConverter.fromRestObject(obj.sellSettings);
t.buySettings = obj.buySettings == null ? null : tsConverter.fromRestObject(obj.buySettings);
t.sellSettings = obj.sellSettings == null ? null : tsConverter.fromRestObject(obj.sellSettings);
t.symbol = TradingPairs.fromString(obj.symbol);
return t;