Compare commits

...

2 Commits

11 changed files with 172 additions and 15 deletions

View File

@ -260,7 +260,7 @@ export default class BinanceApiClient extends APIClient {
"symbol": transaction.symbol.getKey(), "symbol": transaction.symbol.getKey(),
"side": "BUY", "side": "BUY",
"type": "LIMIT", "type": "LIMIT",
"price": transaction.buySettings.oderPrice, "price": transaction.buySettings.orderPrice,
"quantity" : transaction.buySettings.orderQuantity, "quantity" : transaction.buySettings.orderQuantity,
"newClientOrderId": transaction.id, "newClientOrderId": transaction.id,
"timeInForce": "GTC", "timeInForce": "GTC",
@ -283,7 +283,7 @@ export default class BinanceApiClient extends APIClient {
"symbol": transaction.symbol.getKey(), "symbol": transaction.symbol.getKey(),
"side": "SELL", "side": "SELL",
"type": "LIMIT", "type": "LIMIT",
"price": transaction.sellSettings.oderPrice, "price": transaction.sellSettings.orderPrice,
"quantity" : transaction.sellSettings.orderQuantity, "quantity" : transaction.sellSettings.orderQuantity,
"newClientOrderId": transaction.id, "newClientOrderId": transaction.id,
"timeInForce": "GTC", "timeInForce": "GTC",

View File

@ -11,7 +11,7 @@ export default class TransactionSettings extends Serializable{
* ordered price * ordered price
* @type {number} * @type {number}
*/ */
oderPrice = 0; orderPrice = 0;
/** /**
* real quantity * real quantity
@ -37,7 +37,7 @@ export default class TransactionSettings extends Serializable{
*/ */
constructor(price = 0, quantity = 0){ constructor(price = 0, quantity = 0){
super(); super();
this.oderPrice = price; this.orderPrice = price;
this.orderQuantity = quantity; this.orderQuantity = quantity;
} }
@ -47,7 +47,7 @@ export default class TransactionSettings extends Serializable{
toJson() { toJson() {
const obj = JSON.parse(super.toJson()); const obj = JSON.parse(super.toJson());
obj.orderQuantity = this.orderQuantity; obj.orderQuantity = this.orderQuantity;
obj.oderPrice = this.oderPrice; obj.oderPrice = this.orderPrice;
obj.quantity = this.quantity; obj.quantity = this.quantity;
obj.price = this.price; obj.price = this.price;
obj.apiID = this.apiID; obj.apiID = this.apiID;
@ -64,7 +64,7 @@ export default class TransactionSettings extends Serializable{
const tmpObj = JSON.parse(objString); const tmpObj = JSON.parse(objString);
obj.orderQuantity = tmpObj.orderQuantity; obj.orderQuantity = tmpObj.orderQuantity;
obj.oderPrice = tmpObj.oderPrice; obj.orderPrice = tmpObj.oderPrice;
obj.quantity = tmpObj.quantity; obj.quantity = tmpObj.quantity;
obj.price = tmpObj.price; obj.price = tmpObj.price;
obj.apiID = tmpObj.apiID; obj.apiID = tmpObj.apiID;

View File

@ -20,13 +20,15 @@ import StatisticWorker from "./tradingbot/worker/StatisticWorker.js";
import PeakDetector from "./tradingbot/data/asset/PeakDetector.js"; import PeakDetector from "./tradingbot/data/asset/PeakDetector.js";
import OrderBookEntry from "./apiwrapper/orderbook/OrderBookEntry.js"; import OrderBookEntry from "./apiwrapper/orderbook/OrderBookEntry.js";
import TestStrategy from "./tradingbot/strategy/TestStrategy.js"; import TestStrategy from "./tradingbot/strategy/TestStrategy.js";
import AvgMinMaxStrategy from "./tradingbot/strategy/AvgMinMaxStrategy.js";
try{ try{
const tradingBot = new TradingBot("C:/Users/Wlad/Projekte/BinanceBot/binance_bot/data/conf", "config-test.sjson"); const tradingBot = new TradingBot("C:/Users/Wlad/Projekte/BinanceBot/binance_bot/data/conf", "config-test.sjson");
const galaWorker = new DefaultWorker("default_gala", TradingPairs.GALAUSDT, new AbstractStrategy()); const galaWorker = new DefaultWorker("gala_minmax", TradingPairs.GALAUSDT, new AvgMinMaxStrategy());
const statWorker = new StatisticWorker("gala_stats", TradingPairs.GALAUSDT, new TestStrategy()); const statWorker = new StatisticWorker("gala_stats", TradingPairs.GALAUSDT, new TestStrategy());
tradingBot.registerWorker(galaWorker); //tradingBot.registerWorker(galaWorker);
tradingBot.registerWorker(statWorker); //tradingBot.registerWorker(statWorker);
tradingBot.start(); tradingBot.start();
} catch (e){ } catch (e){
console.log(e); console.log(e);
@ -95,11 +97,13 @@ try{
// ############################ // ############################
/*const path = 'C:/Users/Wlad/Projekte/BinanceBot/binance_bot/data/conf'; /*const path = 'C:/Users/Wlad/Projekte/BinanceBot/binance_bot/data/conf';
const conf = new BotConfig(); const conf = new BotConfig();
conf.setApiConfig(BinanceApiConfig.createMainNetConfig()); conf.setApiConfig(BinanceApiConfig.createTestNetConfig());
conf.setWorkingDirectory('C:/Users/Wlad/Desktop/binance_bot'); conf.setWorkingDirectory('C:/Users/Wlad/Projekte/BinanceBot/binance_bot/data');
conf.setRelativeDataPath('data'); conf.setRelativeDataPath('data');
conf.setRelativeLogPath('logs'); conf.setRelativeLogPath('logs');
conf.setRelativeTmpPath('tmp'); conf.setRelativeTmpPath('tmp');
conf.setUsdTradeLimit(500);
conf.setPerTradeLimit(30);
SerializableHelper.save(path, "config-test.sjson", conf);*/ SerializableHelper.save(path, "config-test.sjson", conf);*/
// ############################ // ############################

View File

@ -71,7 +71,7 @@ export default class AssetDataCollector {
const tp = tradingPair instanceof TradingPair ? tradingPair : TradingPairs.fromString(symbol); const tp = tradingPair instanceof TradingPair ? tradingPair : TradingPairs.fromString(symbol);
if(!this.#assetMap.has(tp.getKey())){ if(!this.#assetMap.has(tp.getKey())){
this.#assetMap.set(tp.getKey(), new AssetData(tp, this.#config.getDataCollectionConfig())); this.#assetMap.set(tp.getKey(), new AssetData(tp));
} }
return this.#assetMap.get(tp.getKey()); return this.#assetMap.get(tp.getKey());

View File

@ -344,12 +344,12 @@ export default class TradingBot {
* @param {number} price * @param {number} price
*/ */
requestBuy(worker, quantity, price){ requestBuy(worker, quantity, price){
if(this.#config.getUsdTradeLimit() / this.#config.getPerTradeLimit() >= this.#transactions.length){ if(this.#config.getUsdTradeLimit() / this.#config.getPerTradeLimit() <= this.#transactions.length){
return; return;
} }
const transaction = new Transaction(worker.getId(), worker.getTradingPair()); const transaction = new Transaction(worker.getId(), worker.getTradingPair());
transaction.buySettings.oderPrice = price; transaction.buySettings.orderPrice = price;
transaction.buySettings.orderQuantity = Math.round(this.#config.getPerTradeLimit() / price); transaction.buySettings.orderQuantity = Math.round(this.#config.getPerTradeLimit() / price);
this.#transactions.push(transaction); this.#transactions.push(transaction);
this.#saveTransactions(); this.#saveTransactions();

View File

@ -0,0 +1,33 @@
import AggregatedDataPoint from "../data/asset/AggregatedDataPoint";
export default class AssetInstrumentCalculator{
/**
* Calculate simple moving average
*
* Formula: SMA = (A1 + A2 + .An) / n
*
* @param {AggregatedDataPoint[]} dataPoints
* @returns {number}
*/
static calculateSMA(dataPoints) {
return dataPoints.map(dp => dp.avgPrice).reduce((a, b) => a+b, 0) / dataPoints.length;
}
/**
* Calculate exponential moving average
*
* Formula: EMA = [Closing Price EMA (Previous Time Period)] x Multiplier + EMA (Previous Time Period)
*
* SMA is taken as EMA of previous period; Multiplier ist 2/(n+1)
*
* @param {AggregatedDataPoint[]} dataPoints
* @returns {number}
*/
static caclulateEMA(dataPoints) {
const sma = AssetInstrumentCalculator.calculateSMA(dataPoints);
const multiplier = 2 / (dataPoints.length + 1);
return sma * (1 - multiplier) + dataPoints[dataPoints.length - 1] * multiplier;
}
}

View File

@ -27,7 +27,7 @@ export default class DefaultWorker extends AbstractWorker{
* @param {Transaction[]} transactions * @param {Transaction[]} transactions
*/ */
onUpdate(assetData, transactions){ onUpdate(assetData, transactions){
this.getStrategy().updateAssetData(assetData); this.getStrategy().setAssetData(assetData);
const price = this.getStrategy().getAssetData().getOrderBook().getBestBid().price; const price = this.getStrategy().getAssetData().getOrderBook().getBestBid().price;
if(this.getStrategy().shouldBuy()){ if(this.getStrategy().shouldBuy()){

View File

@ -4,6 +4,7 @@ import cors from "cors";
import WebViewDataProvider from "./WebViewDataProvider.js"; import WebViewDataProvider from "./WebViewDataProvider.js";
import ConverterFactory from "./converter/ConverterFactory.js"; import ConverterFactory from "./converter/ConverterFactory.js";
import AggregatedDataPointConverter from "./converter/converters/AggregatedDataPointConverter.js"; import AggregatedDataPointConverter from "./converter/converters/AggregatedDataPointConverter.js";
import TransactionConverter from "./converter/converters/TransactionConverter.js";
export default class RestClient { export default class RestClient {
@ -64,6 +65,10 @@ export default class RestClient {
res.json(this.#getAssetOrderBook(req.params.symbol)); res.json(this.#getAssetOrderBook(req.params.symbol));
}); });
this.#service.get("/asset/:symbol/transactions", (req, res, next) => {
res.json(this.#getTransactions(req.params.symbol, req.query.type));
});
this.#service.get("/asset/:symbol/aggregated", (req, res, next) => { this.#service.get("/asset/:symbol/aggregated", (req, res, next) => {
res.json(this.#getAggregatedAssetData(req.params.symbol, req.query.startTime, req.query.duration)); res.json(this.#getAggregatedAssetData(req.params.symbol, req.query.startTime, req.query.duration));
}); });
@ -100,6 +105,14 @@ export default class RestClient {
return ConverterFactory.getConverter(orderBook).toRestObject(orderBook); return ConverterFactory.getConverter(orderBook).toRestObject(orderBook);
} }
#getTransactions(asset, type = null){
const allTransactions = type == "all";
const transactions = allTransactions ? this.#dataProvider.getAllTransactions(asset) : this.#dataProvider.getActiveTransactions(asset);
const transactionConverter = new TransactionConverter();
return transactions.map(t => transactionConverter.toRestObject(t));
}
#getAllOrderBooks(){ #getAllOrderBooks(){
const orderBooks = []; const orderBooks = [];

View File

@ -1,15 +1,21 @@
import OrderBook from "../../apiwrapper/orderbook/OrderBook.js"; import OrderBook from "../../apiwrapper/orderbook/OrderBook.js";
import OrderBookEntry from "../../apiwrapper/orderbook/OrderBookEntry.js"; import OrderBookEntry from "../../apiwrapper/orderbook/OrderBookEntry.js";
import Transaction from "../../apiwrapper/transaction/Transaction.js";
import TransactionSettings from "../../apiwrapper/transaction/TransactionSettings.js";
import AggregatedDataPoint from "../../tradingbot/data/asset/AggregatedDataPoint.js"; import AggregatedDataPoint from "../../tradingbot/data/asset/AggregatedDataPoint.js";
import AbstractConverter from "./AbstractConverter.js"; import AbstractConverter from "./AbstractConverter.js";
import AggregatedDataPointConverter from "./converters/AggregatedDataPointConverter.js"; import AggregatedDataPointConverter from "./converters/AggregatedDataPointConverter.js";
import OrderBookConverter from "./converters/OrderBookConverter.js"; import OrderBookConverter from "./converters/OrderBookConverter.js";
import OrderBookEntryConverter from "./converters/OrderBookEntryConverter.js"; import OrderBookEntryConverter from "./converters/OrderBookEntryConverter.js";
import TransactionConverter from "./converters/TransactionConverter.js";
import TransactionSettingsConverter from "./converters/TransactionSettingsConverter.js";
export default class ConverterFactory { export default class ConverterFactory {
static OBJECT_TYPE_ORDER_BOOK = 'order_book'; static OBJECT_TYPE_ORDER_BOOK = 'order_book';
static OBJECT_TYPE_ORDER_BOOK_ENTRY = 'order_book_entry'; static OBJECT_TYPE_ORDER_BOOK_ENTRY = 'order_book_entry';
static OBJECT_TYPE_AGGREGATED_DATA_POINT = 'aggregated_data_point'; static OBJECT_TYPE_AGGREGATED_DATA_POINT = 'aggregated_data_point';
static OBJECT_TYPE_TRANSACTION = 'transaction';
static OBJECT_TYPE_TRANSACTION_SETTINGS = 'transaction_settings';
/** /**
* @param {any} obj * @param {any} obj
@ -30,6 +36,10 @@ export default class ConverterFactory {
return new OrderBookEntryConverter(); return new OrderBookEntryConverter();
} else if (obj instanceof AggregatedDataPoint){ } else if (obj instanceof AggregatedDataPoint){
return new AggregatedDataPointConverter(); return new AggregatedDataPointConverter();
} else if (obj instanceof Transaction){
return new TransactionConverter();
} else if (obj instanceof TransactionSettings){
return new TransactionSettingsConverter();
} }
throw new Error("No converter defined for: " + JSON.stringify(obj)); throw new Error("No converter defined for: " + JSON.stringify(obj));
@ -47,6 +57,10 @@ export default class ConverterFactory {
return new OrderBookEntryConverter(); return new OrderBookEntryConverter();
case this.OBJECT_TYPE_AGGREGATED_DATA_POINT: case this.OBJECT_TYPE_AGGREGATED_DATA_POINT:
return new AggregatedDataPointConverter(); return new AggregatedDataPointConverter();
case this.OBJECT_TYPE_TRANSACTION:
return new TransactionConverter();
case this.OBJECT_TYPE_TRANSACTION_SETTINGS:
return new TransactionSettingsConverter();
default: default:
throw new Error("No converter defined for type: " + type); throw new Error("No converter defined for type: " + type);
} }

View File

@ -0,0 +1,52 @@
import TradingPairs from "../../../apiwrapper/assets/TraidingPairs.js";
import Transaction from "../../../apiwrapper/transaction/Transaction.js";
import AbstractConverter from "../AbstractConverter.js";
import ConverterFactory from "../ConverterFactory.js";
import TransactionSettingsConverter from "./TransactionSettingsConverter.js";
export default class TransactionConverter extends AbstractConverter {
constructor(){
super();
}
/**
* @param {Transaction} obj
* @returns {object}
*/
toRestObject(obj) {
const tsConverter = new TransactionSettingsConverter();
return {
_objectType: ConverterFactory.OBJECT_TYPE_TRANSACTION,
id: obj.id,
initiator: obj.initiator,
phase: obj.phase,
timestamp:obj.timestamp,
result: obj.result,
buySettings: tsConverter.toRestObject(obj.buySettings),
sellSettings: tsConverter.toRestObject(obj.sellSettings),
symbol: obj.symbol.getKey()
};
}
/**
* @param {object} obj
* @returns {Transaction}
*/
fromRestObject(obj) {
const t = new Transaction(null, null);
const tsConverter = new TransactionSettingsConverter();
t.id = obj.id;
t.initiator = obj.initiator;
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.symbol = TradingPairs.fromString(obj.symbol);
return t;
}
}

View File

@ -0,0 +1,41 @@
import TransactionSettings from "../../../apiwrapper/transaction/TransactionSettings.js";
import AbstractConverter from "../AbstractConverter.js";
import ConverterFactory from "../ConverterFactory.js";
export default class TransactionSettingsConverter extends AbstractConverter {
constructor(){
super();
}
/**
* @param {TransactionSettings} obj
* @returns {object}
*/
toRestObject(obj) {
return {
_objectType: ConverterFactory.OBJECT_TYPE_TRANSACTION_SETTINGS,
id: obj.apiID,
orderPrice: obj.orderPrice,
orderQuantity: obj.orderQuantity,
price: obj.price,
quantity: obj.quantity
};
}
/**
* @param {object} obj
* @returns {TransactionSettings}
*/
fromRestObject(obj) {
const ts = new TransactionSettings(null, null);
ts.apiID = obj.id;
ts.orderPrice = obj.orderPrice;
ts.orderQuantity = obj.orderQuantity;
ts.price = obj.price;
ts.quantity = obj.quantity;
return ts;
}
}