[#27] Ausbau von TimedAssetData und erstzung durch AggregatedData

This commit is contained in:
darkeye 2025-01-11 20:35:16 +01:00
parent e002eeec44
commit adbe4f30c8
15 changed files with 76 additions and 609 deletions

View File

@ -25,8 +25,8 @@ 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("default_gala", TradingPairs.GALAUSDT, new AbstractStrategy());
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);

View File

@ -2,7 +2,6 @@ import BinanceApiConfig from "../../apis/binance/BinanceApiConfig.js";
import APIConfig from "../../apiwrapper/APIConfig.js"; import APIConfig from "../../apiwrapper/APIConfig.js";
import Serializable from "../../util/Serializable.js"; import Serializable from "../../util/Serializable.js";
import SerializableHelper from "../../util/SerializableHelper.js"; import SerializableHelper from "../../util/SerializableHelper.js";
import AssetDataCollectionConfig from "../data/asset/AssetDataCollectionConfig.js";
export default class BotConfig extends Serializable { export default class BotConfig extends Serializable {
/** /**
@ -30,11 +29,6 @@ export default class BotConfig extends Serializable {
*/ */
#apiConfig = new BinanceApiConfig(); #apiConfig = new BinanceApiConfig();
/**
* @type {AssetDataCollectionConfig}
*/
#dataCollectionConfig = new AssetDataCollectionConfig(['1s', '1m', '15m', '1h']);
/** /**
* @type {string} chrono unit string; Time until trading should start * @type {string} chrono unit string; Time until trading should start
*/ */
@ -211,20 +205,6 @@ export default class BotConfig extends Serializable {
this.#restInterfacePort = port; this.#restInterfacePort = port;
} }
/**
* @param {AssetDataCollectionConfig} conf
*/
setDataCollectionConfig(conf){
this.#dataCollectionConfig = conf;
}
/**
* @returns {AssetDataCollectionConfig}
*/
getDataCollectionConfig(){
return this.#dataCollectionConfig;
}
/** /**
* @returns {string} chrono time string * @returns {string} chrono time string
*/ */
@ -253,7 +233,6 @@ export default class BotConfig extends Serializable {
obj.singleTradeLimit = this.#maxUSDPerTrade; obj.singleTradeLimit = this.#maxUSDPerTrade;
obj.restInterfaceEnabled = this.#enableRestInterface; obj.restInterfaceEnabled = this.#enableRestInterface;
obj.restInterfacePort = this.#restInterfacePort; obj.restInterfacePort = this.#restInterfacePort;
obj.assetDataCollectionConfig = SerializableHelper.serialize(this.#dataCollectionConfig);
obj.rampupTime = this.#rampupTime; obj.rampupTime = this.#rampupTime;
return JSON.stringify(obj); return JSON.stringify(obj);
@ -276,7 +255,6 @@ export default class BotConfig extends Serializable {
conf.#maxUSDPerTrade = obj.singleTradeLimit; conf.#maxUSDPerTrade = obj.singleTradeLimit;
conf.#enableRestInterface = obj.restInterfaceEnabled; conf.#enableRestInterface = obj.restInterfaceEnabled;
conf.#restInterfacePort = obj.restInterfacePort; conf.#restInterfacePort = obj.restInterfacePort;
conf.#dataCollectionConfig = SerializableHelper.deserialize(obj.assetDataCollectionConfig);
conf.#rampupTime = obj.rampupTime; conf.#rampupTime = obj.rampupTime;
return conf; return conf;

View File

@ -148,7 +148,6 @@ export default class AggregatedDataPoint {
this.#priceValues.forEach(p => priceSum += p); this.#priceValues.forEach(p => priceSum += p);
this.avgPrice = priceSum / this.#priceValues.length; this.avgPrice = priceSum / this.#priceValues.length;
} }
console.log(this.minPrice, this.maxPrice, this.avgPrice, this.minPrice <= this.avgPrice, this.avgPrice <= this.maxPrice);
this.#priceValues = []; this.#priceValues = [];
} }

View File

@ -5,21 +5,14 @@ import Ticker24hEvent from "../../../apiwrapper/event/Ticker24hEvent.js";
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 AssetDataAggregator from "./AssetDataAggregator.js"; import AssetDataAggregator from "./AssetDataAggregator.js";
import AssetDataCollectionConfig from "./AssetDataCollectionConfig.js";
import PeakDetector from "./PeakDetector.js"; import PeakDetector from "./PeakDetector.js";
import TimedAssetData from "./TimedAssetData.js";
export default class AssetData extends TimedAssetData { export default class AssetData {
/** /**
* @type {TradingPair} * @type {TradingPair}
*/ */
#tradingPair = null; #tradingPair = null;
/**
* @type {AssetDataCollectionConfig}
*/
#config = null;
/** /**
* @type {number} * @type {number}
*/ */
@ -73,16 +66,13 @@ export default class AssetData extends TimedAssetData {
/** /**
* @type {AssetDataAggregator} * @type {AssetDataAggregator}
*/ */
assetDataAggregator = new AssetDataAggregator(); #assetDataAggregator = new AssetDataAggregator();
/** /**
* @param {TradingPair} tradingPair * @param {TradingPair} tradingPair
* @param {AssetDataCollectionConfig} collectionConfig
*/ */
constructor(tradingPair, collectionConfig) { constructor(tradingPair) {
super([31536000000, ...collectionConfig.getTimePeriodsInMs()]);
this.#tradingPair = tradingPair; this.#tradingPair = tradingPair;
this.open();
} }
/** /**
@ -103,8 +93,7 @@ export default class AssetData extends TimedAssetData {
* @param {KLineEvent} klineEvent * @param {KLineEvent} klineEvent
*/ */
updateKline(klineEvent) { updateKline(klineEvent) {
this.push(klineEvent.high, klineEvent.low, klineEvent.open, klineEvent.close); this.#assetDataAggregator.pushKLine(klineEvent.timestamp, klineEvent.low, klineEvent.high, klineEvent.open, klineEvent.close);
this.assetDataAggregator.pushKLine(klineEvent.timestamp, klineEvent.low, klineEvent.high, klineEvent.open, klineEvent.close);
} }
/** /**
@ -112,11 +101,9 @@ export default class AssetData extends TimedAssetData {
*/ */
updateOrderBook(orderBookUpdateEvent){ updateOrderBook(orderBookUpdateEvent){
this.#orderBook.update(orderBookUpdateEvent); this.#orderBook.update(orderBookUpdateEvent);
this.pushBestBid(this.#orderBook.getBestBid());
this.pushBestAsk(this.#orderBook.getBestAsk());
this.#peakDetector.push(this.#orderBook.getBestAsk()); this.#peakDetector.push(this.#orderBook.getBestAsk());
this.assetDataAggregator.pushBestAsk(this.#orderBook.getBestAsk()); this.#assetDataAggregator.pushBestAsk(this.#orderBook.getBestAsk());
this.assetDataAggregator.pushBestBid(this.#orderBook.getBestBid()); this.#assetDataAggregator.pushBestBid(this.#orderBook.getBestBid());
} }
/** /**
@ -183,28 +170,16 @@ export default class AssetData extends TimedAssetData {
return this.#trades24h; return this.#trades24h;
} }
/**
* @param {number} high
* @param {number} low
* @param {number} open
* @param {number} close
*/
push(high, low, open, close) {
super.push(high, low, open, close);
const slots = this.getSubData();
for(let i = slots.length - 2; i >= 0; i--){
slots[i].removeSubData();
}
}
/** /**
* @param {number} time * @param {number} time
* @param {number} price * @param {number} price
* @param {number} quantity * @param {number} quantity
*/ */
pushTrade(time, price, quantity) { pushTrade(time, price, quantity) {
super.pushTrade(time, price, quantity); this.#assetDataAggregator.pushTrade(time, price, quantity);
this.assetDataAggregator.pushTrade(time, price, quantity);
} }
getAggregatedData(duration, timeOffset = -1){
return this.#assetDataAggregator.getData(duration, timeOffset);
}
} }

View File

@ -1,54 +0,0 @@
import Serializable from "../../../util/Serializable.js";
import UnitHelper from "../../util/UnitHelper.js";
export default class AssetDataCollectionConfig extends Serializable{
/**
* @type {number[]}
*/
#timePeriods = [];
/**
* @param {string[]|number[]|null} timePeriods
*/
constructor(timePeriods = null) {
super();
this.setTimePeriods(timePeriods);
}
/**
* @param {string[]|number[]|null} timePeriods
*/
setTimePeriods(timePeriods){
if(timePeriods != null){
for (const timePeriod of timePeriods) {
this.#timePeriods.push(UnitHelper.formatedDurationToMs(timePeriod));
}
}
}
getTimePeriodsInMs(){
return [...this.#timePeriods.sort((a, b) => a - b)];
}
/**
* @returns {string} string representation of this object
*/
toJson() {
const obj = JSON.parse(super.toJson());
obj.timePeriods = this.#timePeriods;
return JSON.stringify(obj);
}
/**
* @param {string} objString
* @returns {AssetDataCollectionConfig}
*/
static fromJson(objString) {
const obj = JSON.parse(objString);
const timePeriodConfig = new AssetDataCollectionConfig(obj.timePeriods);
return timePeriodConfig;
}
}

View File

@ -1,6 +0,0 @@
export default class AssetStatisticValue{
min1 = 0;
min15 = 0;
min30 = 0;
min60 = 0;
}

View File

@ -1,369 +0,0 @@
import OrderBookEntry from "../../../apiwrapper/orderbook/OrderBookEntry.js";
import UnitHelper from "../../util/UnitHelper.js";
import TimedAssetDataMerger from "./TimedAssetDataMerger.js";
export default class TimedAssetData {
/**
* @type {number}
*/
#duration = 0;
/**
* @type {number}
*/
#startTime = 0;
/**
* @type {number}
*/
#endTime = 0;
/**
* @type {boolean}
*/
#closed = false;
/**
* @type {number}
*/
#open = 0;
/**
* @type {number}
*/
#close = 0;
/**
* @type {number}
*/
#high = Number.MIN_VALUE;
/**
* @type {number}
*/
#low = Number.MAX_VALUE;
/**
* @type {number}
*/
#volume = 0;
/**
* @type {number}
*/
#trades = 0;
/**
* @type {OrderBookEntry}
*/
#bestBid = null;
/**
* @type {OrderBookEntry}
*/
#bestAsk = null;
/**
* @type {TimedAssetData[]}
*/
#subSlots = [];
/**
* @type {number[]}
*/
#subSlotDurations = [];
/**
* @param {number[]} durations
*/
constructor(durations) {
this.#duration = durations.pop();
this.#subSlotDurations = [...durations];
}
/**
* @param {number} startTime
*/
open(startTime) {
if (startTime != null) {
this.#startTime = startTime;
} else {
this.#startTime = Date.now();
}
this.#closed = false;
}
/**
* @param {number} endTime
*/
close(endTime) {
if (this.#closed) {
return;
}
if (endTime != null) {
this.#endTime = endTime;
} else {
this.#endTime = Date.now();
}
this.#closed = true;
if (this.#subSlots != null && this.#subSlots.length > 0) {
this.#subSlots[this.#subSlots.length - 1].close(endTime);
}
}
removeSubData() {
if (!this.#closed) {
return;
}
this.#subSlots.forEach(slot => {slot.close(); slot.removeSubData()});
this.#subSlots = [];
}
/**
* @returns {TimedAssetData[]}
*/
getSubData() {
return this.#subSlots;
}
/**
* @type {TimedAssetData}
*/
getSlotForPeriode(chronoString){
const periode = UnitHelper.formatedDurationToMs(chronoString);
if(this.getDuration() <= periode){
return this;
}
if(this.#subSlotDurations == null || this.#subSlotDurations.length == 0){
return null;
}
const subSlotDuration = this.#subSlotDurations[this.#subSlotDurations.length - 1];
if(subSlotDuration > periode){
const lastSlotIndex = this.#subSlots.length - 1;
if((this.#subSlots[lastSlotIndex].getEndTime() - this.#subSlots[lastSlotIndex].getStartTime()) >= periode * 0.7){
return this.#subSlots[lastSlotIndex].getSlotForPeriode(periode);
} else {
return this.#subSlots[Math.max(lastSlotIndex-1), 0].getSlotForPeriode(periode);
}
}
const merger = new TimedAssetDataMerger();
for(let i = this.#subSlots.length - 1, duration = 0; i >= 0 && duration < periode; i--){
merger.push(this.#subSlots[i]);
duration += this.#subSlots[i].getEndTime() - this.#subSlots[i].getStartTime();
}
return merger.merge(periode);
}
/**
* @returns {number}
*/
getDuration() {
return this.#duration;
}
/**
* @param {number} duration
*/
setDuration(duration){
this.#duration = duration;
}
/**
* @returns {number}
*/
getStartTime() {
return this.#startTime;
}
/**
* @returns {number}
*/
getEndTime() {
return this.#endTime != 0 ? this.#endTime : Date.now();
}
/**
* @returns {number}
*/
getOpen() {
return this.#open;
}
/**
* @returns {number}
*/
getClose() {
return this.#close;
}
/**
* @returns {number}
*/
getHigh() {
return this.#high;
}
/**
* @returns {number}
*/
getLow() {
return this.#low;
}
/**
* @returns {number}
*/
getVolume() {
return this.#volume;
}
/**
* @returns {number}
*/
getTrades() {
return this.#trades;
}
/**
* @returns {OrderBookEntry}
*/
getBestBid() {
return this.#bestBid;
}
/**
* @returns {OrderBookEntry}
*/
getBestAsk() {
return this.#bestAsk;
}
/**
* @param {number} time
* @returns {boolean}
*/
isInSlot(time) {
if (this.#closed) {
return false;
}
return (time - this.#startTime) < this.#duration;
}
/**
* @param {number} high
* @param {number} low
* @param {number} open
* @param {number} close
*/
push(high, low, open, close) {
this.#high = Math.max(this.#high, high);
this.#low = Math.min(this.#low, low);
this.#close = close;
if (this.#open <= 0) {
this.#open = open;
}
const subSlot = this.#getSubSlot();
if (subSlot) {
subSlot.push(high, low, open, close);
}
}
/**
*
* @param {number} time
* @param {number} price
* @param {number} quantity
*/
pushTrade(time, price, quantity) {
this.#trades ++;
this.#volume += quantity;
const subSlot = this.#getSubSlot();
if (subSlot) {
subSlot.pushTrade(time, price, quantity);
}
}
/**
* @param {number} count
* @param {number} avgPrice
* @param {number} quantity
*/
setTradeValues(count, avgPrice, quantity){
this.#trades = count;
this.#volume = quantity;
}
/**
*
* @param {OrderBookEntry} ask
*/
pushBestAsk(ask) {
if (this.#bestAsk == null || this.#bestAsk.price < ask.price) {
this.#bestAsk = ask;
}
const subSlot = this.#getSubSlot();
if (subSlot) {
subSlot.pushBestAsk(ask);
}
}
/**
*
* @param {OrderBookEntry} bid
*/
pushBestBid(bid) {
if (this.#bestBid == null || this.#bestBid.price > bid.price) {
this.#bestBid = bid;
}
const subSlot = this.#getSubSlot();
if (subSlot) {
subSlot.pushBestBid(bid);
}
}
/**
*
* @returns {TimeSlot}
*/
#getSubSlot() {
if (this.#subSlotDurations == null || this.#subSlotDurations.length < 1) {
return null;
}
let activeSubSlot = null;
if (this.#subSlots.length == 0) {
activeSubSlot = new TimedAssetData([...this.#subSlotDurations]);
activeSubSlot.open(Date.now());
this.#subSlots.push(activeSubSlot);
} else {
activeSubSlot = this.#subSlots[this.#subSlots.length - 1];
if (!activeSubSlot.isInSlot(Date.now())) {
activeSubSlot.close(Date.now());
activeSubSlot = new TimedAssetData([...this.#subSlotDurations]);
activeSubSlot.open(Date.now());
this.#subSlots.push(activeSubSlot);
}
}
return activeSubSlot;
}
}

View File

@ -1,70 +0,0 @@
import OrderBookEntry from "../../../apiwrapper/orderbook/OrderBookEntry.js";
import TimedAssetData from "./TimedAssetData.js";
export default class TimedAssetDataMerger {
/**
* @type {TimedAssetData[]}
*/
#slotsToMerge = []
/**
* @param {TimedAssetData} data
*/
push(data){
this.#slotsToMerge.push(data);
}
/**
* @param {number} expectedDuration duration of the new slot or null for sum of all given durations
* @returns {TimedAssetData}
*/
merge(expectedDuration = null){
if(this.#slotsToMerge.length == 0){
return null;
}
this.#slotsToMerge.sort((s1, s2) => s1.getStartTime() - s2.getStartTime());
const result = new TimedAssetData([0]);
let shortestSlotDuration = this.#slotsToMerge[0].getEndTime() - this.#slotsToMerge[0].getStartTime();
this.#slotsToMerge.forEach(s => {
shortestSlotDuration = Math.min(shortestSlotDuration, s.getEndTime() - s.getStartTime());
});
let newSlotDuration = 0;
let open = 0;
let close = 0;
let high = Number.MIN_VALUE;
let low = Number.MAX_VALUE;
let tradeCount = 0;
let tradeVolume = 0;
for(let i = this.#slotsToMerge.length - 1; i >= 0 && (expectedDuration == null || newSlotDuration < expectedDuration); i--){
let factor = this.#slotsToMerge[i].getDuration() / shortestSlotDuration;
if(expectedDuration != null && newSlotDuration + this.#slotsToMerge[i].getDuration() > expectedDuration){
factor /= this.#slotsToMerge[i].getDuration() / (expectedDuration - newSlotDuration);
}
open = (open == 0 || factor >= 0.6) ? this.#slotsToMerge[i].getOpen() : open;
close = close == 0 ? this.#slotsToMerge[i].getClose() : close;
high = (high == 0 || factor >= 0.6) ? Math.max(this.#slotsToMerge[i].getHigh(), high) : high;
low = (low == 0 || factor >= 0.6) ? Math.min(this.#slotsToMerge[i].getLow(), low) : low;
tradeCount += factor < 1 ? this.#slotsToMerge[i].getTrades() * factor : this.#slotsToMerge[i].getTrades();
tradeVolume += factor < 1 ? this.#slotsToMerge[i].getVolume() * factor : this.#slotsToMerge[i].getVolume();
if(factor >= 0.6){
result.pushBestAsk(this.#slotsToMerge[i].getBestAsk());
result.pushBestBid(this.#slotsToMerge[i].getBestBid());
}
}
result.open(this.#slotsToMerge[this.#slotsToMerge.length - 1].getEndTime() - newSlotDuration);
result.setDuration(newSlotDuration);
result.push(high, low, open, close);
result.setTradeValues(Math.round(tradeCount), 0, tradeVolume);
result.close(this.#slotsToMerge[this.#slotsToMerge.length - 1].getEndTime());
return result;
}
}

View File

@ -9,9 +9,6 @@ export default class AvgMinMaxStrategy extends AbstractStrategy {
this.#lastBuySuggestionTime = Date.now(); this.#lastBuySuggestionTime = Date.now();
} }
updateAssetData(assetData) {
}
/** /**
* @param {Transaction} transaction * @param {Transaction} transaction
* @returns {boolean} * @returns {boolean}
@ -23,27 +20,26 @@ export default class AvgMinMaxStrategy extends AbstractStrategy {
return false; return false;
} }
const assetData15Min = this.getAssetData().getSlotForPeriode('15m'); const aggDataPoints = this.getAssetData().getAggregatedData('15m');
const price = this.getAssetData().getOrderBook().getBestBid().price; const price = this.getAssetData().getOrderBook().getBestBid().price;
const avg15m = (assetData15Min.getLow() + assetData15Min.getHigh()) / 2; const avg15m = aggDataPoints.length > 0 ? aggDataPoints.map(v => v.avgPrice).reduce((a, b) => a+b, 0) / aggDataPoints.length : 0;
return avg15m != 0 && avg15m * 1.005 <= price;
return avg15m * 1.005 <= price;
} }
/** /**
* @returns {boolean} * @returns {boolean}
*/ */
shouldBuy() { shouldBuy() {
if(Date.now() < this.#lastBuySuggestionTime + 60000){ if(Date.now() < this.#lastBuySuggestionTime + 300000){
return false; return false;
} }
const assetData15Min = this.getAssetData().getSlotForPeriode('15m'); const aggDataPoints = this.getAssetData().getAggregatedData('15m');
const price = this.getAssetData().getOrderBook().getBestBid().price; const price = this.getAssetData().getOrderBook().getBestBid().price;
const avg15m = (assetData15Min.getLow() + assetData15Min.getHigh()) / 2; const avg15m = aggDataPoints.length > 0 ? aggDataPoints.map(v => v.avgPrice).reduce((a, b) => a+b, 0) / aggDataPoints.length : 0;
if(avg15m * 0.995 >= price){ if(avg15m != 0 && avg15m * 0.995 >= price){
this.#lastBuySuggestionTime = Date.now(); this.#lastBuySuggestionTime = Date.now();
return true; return true;
} }
@ -70,9 +66,9 @@ export default class AvgMinMaxStrategy extends AbstractStrategy {
/** /**
* @param {string} objString * @param {string} objString
* @returns {TestStrategy} * @returns {AvgMinMaxStrategy2}
*/ */
static fromJson(objString) { static fromJson(objString) {
return new Simple24hStrategy(); return new AvgMinMaxStrategy();
} }
} }

View File

@ -9,9 +9,6 @@ export default class PossiblePeakStrategy extends AbstractStrategy {
this.#lastBuySuggestionTime = Date.now(); this.#lastBuySuggestionTime = Date.now();
} }
updateAssetData(assetData) {
}
/** /**
* @param {Transaction} transaction * @param {Transaction} transaction
* @returns {boolean} * @returns {boolean}
@ -35,15 +32,19 @@ export default class PossiblePeakStrategy extends AbstractStrategy {
return false; return false;
} }
const assetData5Min = this.getAssetData().getSlotForPeriode('5m'); const dataPoints15m = this.getAssetData().getAggregatedData('15m');
const assetData15Min = this.getAssetData().getSlotForPeriode('15m');
const avg5Min = (assetData5Min.getLow() + assetData5Min.getHigh()) / 2; if(dataPoints15m.length == 0){
const avg15Min = (assetData15Min.getLow() + assetData15Min.getHigh()) / 2; return false;
const m5min = assetData5Min.getClose() / assetData5Min.getOpen(); }
const avg5Min = dataPoints15m.slice(-5).map(v => v.avgPrice).reduce((a, b) => a+b, 0) / dataPoints15m.length;;
const avg15Min = dataPoints15m.map(v => v.avgPrice).reduce((a, b) => a+b, 0) / dataPoints15m.length;
const m5min = dataPoints15m[0].startPrice / dataPoints15m[dataPoints15m.length - 1].endPrice;
if ((price < avg5Min && avg5Min > avg15Min) if ((price < avg5Min && avg5Min > avg15Min)
|| (price < avg15Min && m5min > 0.9995) || (price < avg15Min && m5min > 0.9995)
|| (price < assetData5Min.getOpen() && price > avg5Min) || (price < dataPoints15m[dataPoints15m.length - 6].startPrice && price > avg5Min)
) { ) {
this.#lastBuySuggestionTime = Date.now(); this.#lastBuySuggestionTime = Date.now();
return true; return true;

View File

@ -9,9 +9,6 @@ export default class Simple24hStrategy extends AbstractStrategy {
this.#lastBuySuggestionTime = Date.now(); this.#lastBuySuggestionTime = Date.now();
} }
updateAssetData(assetData) {
}
/** /**
* @param {Transaction} transaction * @param {Transaction} transaction
* @returns {boolean} * @returns {boolean}
@ -27,13 +24,17 @@ export default class Simple24hStrategy extends AbstractStrategy {
return false; return false;
} }
const assetData15Min = this.getAssetData().getSlotForPeriode('15m'); const grades = this.#getGrades();
const assetData60Min = this.getAssetData().getSlotForPeriode('1h');
const priceChangePercent24h = this.getAssetData().get24hPriceChangePercent();
const grad15min = assetData15Min.getClose() / assetData15Min.getOpen();
const grad60min = assetData60Min.getClose() / assetData60Min.getOpen();
return priceChangePercent24h < 0.05 || (grad15min < 0.995 && grad60min < 0.985); if(grades == null){
return false;
}
const grad15min = grades[0];
const grad60min = grades[1];
const priceChangePercent24h = this.getAssetData().get24hPriceChangePercent();
return priceChangePercent24h < 0.05 || grad15min < grad60min * 0.97;
} }
/** /**
@ -44,11 +45,15 @@ export default class Simple24hStrategy extends AbstractStrategy {
return false; return false;
} }
const assetData15Min = this.getAssetData().getSlotForPeriode('15m'); const grades = this.#getGrades();
const assetData60Min = this.getAssetData().getSlotForPeriode('1h');
if(grades == null){
return false;
}
const grad15min = grades[0];
const grad60min = grades[1];
const priceChangePercent24h = this.getAssetData().get24hPriceChangePercent(); const priceChangePercent24h = this.getAssetData().get24hPriceChangePercent();
const grad15min = (assetData15Min.getClose() - assetData15Min.getOpen()) / 15;
const grad60min = (assetData60Min.getClose() - assetData60Min.getOpen()) / 60;
// up trend // up trend
if(priceChangePercent24h > 2 && grad15min < 0 && grad60min > 0){ if(priceChangePercent24h > 2 && grad15min < 0 && grad60min > 0){
@ -65,6 +70,23 @@ export default class Simple24hStrategy extends AbstractStrategy {
return false; return false;
} }
/**
* @returns {[number, number] | null}
*/
#getGrades(){
const dataPoints1h = this.getAssetData().getAggregatedData('1h');
if(dataPoints1h.length < 60){
return null;
}
const endPrice = dataPoints1h[dataPoints1h.length - 1].endPrice;
const grad15min = (endPrice - dataPoints1h[dataPoints1h - 15].startPrice) / 15;
const grad60min = (endPrice - dataPoints1h[dataPoints1h - 60].startPrice) / 60;
return [grad15min, grad60min];
}
/** /**
* @param {Transaction} transaction * @param {Transaction} transaction
* @returns {boolean} * @returns {boolean}

View File

@ -1,8 +1,6 @@
import Transaction from "../../apiwrapper/transaction/Transaction.js"; import Transaction from "../../apiwrapper/transaction/Transaction.js";
import AbstractStrategy from "./AbstractStrategy.js"; import AbstractStrategy from "./AbstractStrategy.js";
import AvgMinMaxStrategy from "./AvgMinMaxStrategy.js"; import AvgMinMaxStrategy2 from "./AvgMinMaxStrategy.js";
import PossiblePeakStrategy from "./PossiblePeakStrategy.js";
import Simple24hStrategy from "./Simple24hStrategy.js";
export default class TestStrategy extends AbstractStrategy { export default class TestStrategy extends AbstractStrategy {
@ -23,9 +21,7 @@ export default class TestStrategy extends AbstractStrategy {
constructor(){ constructor(){
super(); super();
this.#strategies.push(new Simple24hStrategy()); this.#strategies.push(new AvgMinMaxStrategy2());
this.#strategies.push(new PossiblePeakStrategy());
this.#strategies.push(new AvgMinMaxStrategy());
} }
/** /**

View File

@ -97,7 +97,7 @@ export default class StatisticWorker extends AbstractWorker {
} }
onInit() { onInit() {
this.getLogger().debug("Statistic worker " + this.getName() + " for " + this.getTradingPair().getKey() + " initialized!"); this.getLogger().debug("Statistic 2 worker " + this.getName() + " for " + this.getTradingPair().getKey() + " initialized!");
} }
/** /**
@ -188,18 +188,19 @@ export default class StatisticWorker extends AbstractWorker {
return; return;
} }
this.#lastTickTimestamp = Date.now(); this.#lastTickTimestamp = Date.now();
const lastMinAssetData = assetData.getSlotForPeriode('1m'); const data = assetData.getAggregatedData('2m');
const lastMinAssetData = data != null && data.length > 1 ? data[1] : null;
if (lastMinAssetData == null || lastMinAssetData.getHigh() == Number.MIN_VALUE) { if (lastMinAssetData == null) {
return; return;
} }
const timestamp = Date.now() const timestamp = Date.now()
const peaks = assetData.getPeakDetector().peaks; const peaks = assetData.getPeakDetector().peaks;
this.#peackCount = peaks.length; this.#peackCount = peaks.length;
this.#tradeCount.push([timestamp, lastMinAssetData.getTrades()]); this.#tradeCount.push([timestamp, lastMinAssetData.tradeCount]);
this.#tradeVolume.push([timestamp, lastMinAssetData.getVolume()]); this.#tradeVolume.push([timestamp, lastMinAssetData.tradeVolume]);
this.#price.push([timestamp, lastMinAssetData.getHigh(), lastMinAssetData.getLow(), (lastMinAssetData.getHigh() + lastMinAssetData.getLow()) / 2]); this.#price.push([timestamp, lastMinAssetData.maxPrice, lastMinAssetData.minPrice, lastMinAssetData.avgPrice]);
this.#peakEnd.push([timestamp, false]); this.#peakEnd.push([timestamp, false]);
this.#peakStart.push([timestamp, false]); this.#peakStart.push([timestamp, false]);
this.#buys.push([timestamp, this.#buyCount]); this.#buys.push([timestamp, this.#buyCount]);
@ -240,7 +241,7 @@ export default class StatisticWorker extends AbstractWorker {
/** /**
* @param {string} objString * @param {string} objString
* @returns {AbstractWorker} * @returns {StatisticWorker2}
*/ */
static fromJson(objString) { static fromJson(objString) {
return super.fromJson(objString, new StatisticWorker()); return super.fromJson(objString, new StatisticWorker());

View File

@ -5,7 +5,6 @@ import TradingPair from "../apiwrapper/assets/TradingPair.js";
import Transaction from "../apiwrapper/transaction/Transaction.js"; import Transaction from "../apiwrapper/transaction/Transaction.js";
import TransactionSettings from "../apiwrapper/transaction/TransactionSettings.js"; import TransactionSettings from "../apiwrapper/transaction/TransactionSettings.js";
import BotConfig from "../tradingbot/config/BotConfig.js"; import BotConfig from "../tradingbot/config/BotConfig.js";
import AssetDataCollectionConfig from "../tradingbot/data/asset/AssetDataCollectionConfig.js";
import AbstractStrategy from "../tradingbot/strategy/AbstractStrategy.js"; import AbstractStrategy from "../tradingbot/strategy/AbstractStrategy.js";
import AvgMinMaxStrategy from "../tradingbot/strategy/AvgMinMaxStrategy.js"; import AvgMinMaxStrategy from "../tradingbot/strategy/AvgMinMaxStrategy.js";
import PossiblePeakStrategy from "../tradingbot/strategy/PossiblePeakStrategy.js"; import PossiblePeakStrategy from "../tradingbot/strategy/PossiblePeakStrategy.js";
@ -27,7 +26,6 @@ export default class Serializables {
['AbstractWorker', AbstractWorker], ['AbstractWorker', AbstractWorker],
['StatisticWorker', StatisticWorker], ['StatisticWorker', StatisticWorker],
['DefaultWorker', DefaultWorker], ['DefaultWorker', DefaultWorker],
['AssetDataCollectionConfig', AssetDataCollectionConfig],
['AbstractStrategy', AbstractStrategy], ['AbstractStrategy', AbstractStrategy],
['TestStrategy', TestStrategy], ['TestStrategy', TestStrategy],
['Simple24hStrategy', Simple24hStrategy], ['Simple24hStrategy', Simple24hStrategy],

View File

@ -85,7 +85,7 @@ export default class RestClient {
const st = starttime != null ? starttime : -1; const st = starttime != null ? starttime : -1;
const d = duration != null ? duration : 3600000; const d = duration != null ? duration : 3600000;
const data = this.#dataProvider.getAssetData(asset).assetDataAggregator.getData(d, st); const data = this.#dataProvider.getAssetData(asset).getAggregatedData(d, st);
const converter = new AggregatedDataPointConverter(); const converter = new AggregatedDataPointConverter();
const result = []; const result = [];