[#27] Ausbau von TimedAssetData und erstzung durch AggregatedData
This commit is contained in:
parent
e002eeec44
commit
adbe4f30c8
@ -25,8 +25,8 @@ try{
|
||||
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 statWorker = new StatisticWorker("gala_stats", TradingPairs.GALAUSDT, new TestStrategy());
|
||||
//tradingBot.registerWorker(galaWorker);
|
||||
//tradingBot.registerWorker(statWorker);
|
||||
tradingBot.registerWorker(galaWorker);
|
||||
tradingBot.registerWorker(statWorker);
|
||||
tradingBot.start();
|
||||
} catch (e){
|
||||
console.log(e);
|
||||
|
||||
@ -2,7 +2,6 @@ import BinanceApiConfig from "../../apis/binance/BinanceApiConfig.js";
|
||||
import APIConfig from "../../apiwrapper/APIConfig.js";
|
||||
import Serializable from "../../util/Serializable.js";
|
||||
import SerializableHelper from "../../util/SerializableHelper.js";
|
||||
import AssetDataCollectionConfig from "../data/asset/AssetDataCollectionConfig.js";
|
||||
|
||||
export default class BotConfig extends Serializable {
|
||||
/**
|
||||
@ -30,11 +29,6 @@ export default class BotConfig extends Serializable {
|
||||
*/
|
||||
#apiConfig = new BinanceApiConfig();
|
||||
|
||||
/**
|
||||
* @type {AssetDataCollectionConfig}
|
||||
*/
|
||||
#dataCollectionConfig = new AssetDataCollectionConfig(['1s', '1m', '15m', '1h']);
|
||||
|
||||
/**
|
||||
* @type {string} chrono unit string; Time until trading should start
|
||||
*/
|
||||
@ -211,20 +205,6 @@ export default class BotConfig extends Serializable {
|
||||
this.#restInterfacePort = port;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {AssetDataCollectionConfig} conf
|
||||
*/
|
||||
setDataCollectionConfig(conf){
|
||||
this.#dataCollectionConfig = conf;
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns {AssetDataCollectionConfig}
|
||||
*/
|
||||
getDataCollectionConfig(){
|
||||
return this.#dataCollectionConfig;
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns {string} chrono time string
|
||||
*/
|
||||
@ -253,7 +233,6 @@ export default class BotConfig extends Serializable {
|
||||
obj.singleTradeLimit = this.#maxUSDPerTrade;
|
||||
obj.restInterfaceEnabled = this.#enableRestInterface;
|
||||
obj.restInterfacePort = this.#restInterfacePort;
|
||||
obj.assetDataCollectionConfig = SerializableHelper.serialize(this.#dataCollectionConfig);
|
||||
obj.rampupTime = this.#rampupTime;
|
||||
|
||||
return JSON.stringify(obj);
|
||||
@ -276,7 +255,6 @@ export default class BotConfig extends Serializable {
|
||||
conf.#maxUSDPerTrade = obj.singleTradeLimit;
|
||||
conf.#enableRestInterface = obj.restInterfaceEnabled;
|
||||
conf.#restInterfacePort = obj.restInterfacePort;
|
||||
conf.#dataCollectionConfig = SerializableHelper.deserialize(obj.assetDataCollectionConfig);
|
||||
conf.#rampupTime = obj.rampupTime;
|
||||
|
||||
return conf;
|
||||
|
||||
@ -148,7 +148,6 @@ export default class AggregatedDataPoint {
|
||||
this.#priceValues.forEach(p => priceSum += p);
|
||||
this.avgPrice = priceSum / this.#priceValues.length;
|
||||
}
|
||||
console.log(this.minPrice, this.maxPrice, this.avgPrice, this.minPrice <= this.avgPrice, this.avgPrice <= this.maxPrice);
|
||||
this.#priceValues = [];
|
||||
}
|
||||
|
||||
|
||||
@ -5,21 +5,14 @@ import Ticker24hEvent from "../../../apiwrapper/event/Ticker24hEvent.js";
|
||||
import OrderBook from "../../../apiwrapper/orderbook/OrderBook.js";
|
||||
import OrderBookEntry from "../../../apiwrapper/orderbook/OrderBookEntry.js";
|
||||
import AssetDataAggregator from "./AssetDataAggregator.js";
|
||||
import AssetDataCollectionConfig from "./AssetDataCollectionConfig.js";
|
||||
import PeakDetector from "./PeakDetector.js";
|
||||
import TimedAssetData from "./TimedAssetData.js";
|
||||
|
||||
export default class AssetData extends TimedAssetData {
|
||||
export default class AssetData {
|
||||
/**
|
||||
* @type {TradingPair}
|
||||
*/
|
||||
#tradingPair = null;
|
||||
|
||||
/**
|
||||
* @type {AssetDataCollectionConfig}
|
||||
*/
|
||||
#config = null;
|
||||
|
||||
/**
|
||||
* @type {number}
|
||||
*/
|
||||
@ -73,16 +66,13 @@ export default class AssetData extends TimedAssetData {
|
||||
/**
|
||||
* @type {AssetDataAggregator}
|
||||
*/
|
||||
assetDataAggregator = new AssetDataAggregator();
|
||||
#assetDataAggregator = new AssetDataAggregator();
|
||||
|
||||
/**
|
||||
* @param {TradingPair} tradingPair
|
||||
* @param {AssetDataCollectionConfig} collectionConfig
|
||||
*/
|
||||
constructor(tradingPair, collectionConfig) {
|
||||
super([31536000000, ...collectionConfig.getTimePeriodsInMs()]);
|
||||
constructor(tradingPair) {
|
||||
this.#tradingPair = tradingPair;
|
||||
this.open();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -103,8 +93,7 @@ export default class AssetData extends TimedAssetData {
|
||||
* @param {KLineEvent} 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){
|
||||
this.#orderBook.update(orderBookUpdateEvent);
|
||||
this.pushBestBid(this.#orderBook.getBestBid());
|
||||
this.pushBestAsk(this.#orderBook.getBestAsk());
|
||||
this.#peakDetector.push(this.#orderBook.getBestAsk());
|
||||
this.assetDataAggregator.pushBestAsk(this.#orderBook.getBestAsk());
|
||||
this.assetDataAggregator.pushBestBid(this.#orderBook.getBestBid());
|
||||
this.#assetDataAggregator.pushBestAsk(this.#orderBook.getBestAsk());
|
||||
this.#assetDataAggregator.pushBestBid(this.#orderBook.getBestBid());
|
||||
}
|
||||
|
||||
/**
|
||||
@ -183,28 +170,16 @@ export default class AssetData extends TimedAssetData {
|
||||
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} price
|
||||
* @param {number} 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);
|
||||
}
|
||||
}
|
||||
@ -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;
|
||||
}
|
||||
}
|
||||
@ -1,6 +0,0 @@
|
||||
export default class AssetStatisticValue{
|
||||
min1 = 0;
|
||||
min15 = 0;
|
||||
min30 = 0;
|
||||
min60 = 0;
|
||||
}
|
||||
@ -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;
|
||||
}
|
||||
}
|
||||
@ -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;
|
||||
}
|
||||
}
|
||||
@ -9,9 +9,6 @@ export default class AvgMinMaxStrategy extends AbstractStrategy {
|
||||
this.#lastBuySuggestionTime = Date.now();
|
||||
}
|
||||
|
||||
updateAssetData(assetData) {
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Transaction} transaction
|
||||
* @returns {boolean}
|
||||
@ -23,27 +20,26 @@ export default class AvgMinMaxStrategy extends AbstractStrategy {
|
||||
return false;
|
||||
}
|
||||
|
||||
const assetData15Min = this.getAssetData().getSlotForPeriode('15m');
|
||||
const aggDataPoints = this.getAssetData().getAggregatedData('15m');
|
||||
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 * 1.005 <= price;
|
||||
return avg15m != 0 && avg15m * 1.005 <= price;
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns {boolean}
|
||||
*/
|
||||
shouldBuy() {
|
||||
if(Date.now() < this.#lastBuySuggestionTime + 60000){
|
||||
if(Date.now() < this.#lastBuySuggestionTime + 300000){
|
||||
return false;
|
||||
}
|
||||
|
||||
const assetData15Min = this.getAssetData().getSlotForPeriode('15m');
|
||||
const aggDataPoints = this.getAssetData().getAggregatedData('15m');
|
||||
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();
|
||||
return true;
|
||||
}
|
||||
@ -70,9 +66,9 @@ export default class AvgMinMaxStrategy extends AbstractStrategy {
|
||||
|
||||
/**
|
||||
* @param {string} objString
|
||||
* @returns {TestStrategy}
|
||||
* @returns {AvgMinMaxStrategy2}
|
||||
*/
|
||||
static fromJson(objString) {
|
||||
return new Simple24hStrategy();
|
||||
return new AvgMinMaxStrategy();
|
||||
}
|
||||
}
|
||||
@ -9,9 +9,6 @@ export default class PossiblePeakStrategy extends AbstractStrategy {
|
||||
this.#lastBuySuggestionTime = Date.now();
|
||||
}
|
||||
|
||||
updateAssetData(assetData) {
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Transaction} transaction
|
||||
* @returns {boolean}
|
||||
@ -35,15 +32,19 @@ export default class PossiblePeakStrategy extends AbstractStrategy {
|
||||
return false;
|
||||
}
|
||||
|
||||
const assetData5Min = this.getAssetData().getSlotForPeriode('5m');
|
||||
const assetData15Min = this.getAssetData().getSlotForPeriode('15m');
|
||||
const avg5Min = (assetData5Min.getLow() + assetData5Min.getHigh()) / 2;
|
||||
const avg15Min = (assetData15Min.getLow() + assetData15Min.getHigh()) / 2;
|
||||
const m5min = assetData5Min.getClose() / assetData5Min.getOpen();
|
||||
const dataPoints15m = this.getAssetData().getAggregatedData('15m');
|
||||
|
||||
if(dataPoints15m.length == 0){
|
||||
return false;
|
||||
}
|
||||
|
||||
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)
|
||||
|| (price < avg15Min && m5min > 0.9995)
|
||||
|| (price < assetData5Min.getOpen() && price > avg5Min)
|
||||
|| (price < dataPoints15m[dataPoints15m.length - 6].startPrice && price > avg5Min)
|
||||
) {
|
||||
this.#lastBuySuggestionTime = Date.now();
|
||||
return true;
|
||||
|
||||
@ -9,9 +9,6 @@ export default class Simple24hStrategy extends AbstractStrategy {
|
||||
this.#lastBuySuggestionTime = Date.now();
|
||||
}
|
||||
|
||||
updateAssetData(assetData) {
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Transaction} transaction
|
||||
* @returns {boolean}
|
||||
@ -26,14 +23,18 @@ export default class Simple24hStrategy extends AbstractStrategy {
|
||||
if(winPercent < 0.6){
|
||||
return false;
|
||||
}
|
||||
|
||||
const grades = this.#getGrades();
|
||||
|
||||
const assetData15Min = this.getAssetData().getSlotForPeriode('15m');
|
||||
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 grad15min = assetData15Min.getClose() / assetData15Min.getOpen();
|
||||
const grad60min = assetData60Min.getClose() / assetData60Min.getOpen();
|
||||
|
||||
return priceChangePercent24h < 0.05 || (grad15min < 0.995 && grad60min < 0.985);
|
||||
return priceChangePercent24h < 0.05 || grad15min < grad60min * 0.97;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -44,11 +45,15 @@ export default class Simple24hStrategy extends AbstractStrategy {
|
||||
return false;
|
||||
}
|
||||
|
||||
const assetData15Min = this.getAssetData().getSlotForPeriode('15m');
|
||||
const assetData60Min = this.getAssetData().getSlotForPeriode('1h');
|
||||
const grades = this.#getGrades();
|
||||
|
||||
if(grades == null){
|
||||
return false;
|
||||
}
|
||||
|
||||
const grad15min = grades[0];
|
||||
const grad60min = grades[1];
|
||||
const priceChangePercent24h = this.getAssetData().get24hPriceChangePercent();
|
||||
const grad15min = (assetData15Min.getClose() - assetData15Min.getOpen()) / 15;
|
||||
const grad60min = (assetData60Min.getClose() - assetData60Min.getOpen()) / 60;
|
||||
|
||||
// up trend
|
||||
if(priceChangePercent24h > 2 && grad15min < 0 && grad60min > 0){
|
||||
@ -65,6 +70,23 @@ export default class Simple24hStrategy extends AbstractStrategy {
|
||||
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
|
||||
* @returns {boolean}
|
||||
|
||||
@ -1,8 +1,6 @@
|
||||
import Transaction from "../../apiwrapper/transaction/Transaction.js";
|
||||
import AbstractStrategy from "./AbstractStrategy.js";
|
||||
import AvgMinMaxStrategy from "./AvgMinMaxStrategy.js";
|
||||
import PossiblePeakStrategy from "./PossiblePeakStrategy.js";
|
||||
import Simple24hStrategy from "./Simple24hStrategy.js";
|
||||
import AvgMinMaxStrategy2 from "./AvgMinMaxStrategy.js";
|
||||
|
||||
export default class TestStrategy extends AbstractStrategy {
|
||||
|
||||
@ -23,9 +21,7 @@ export default class TestStrategy extends AbstractStrategy {
|
||||
|
||||
constructor(){
|
||||
super();
|
||||
this.#strategies.push(new Simple24hStrategy());
|
||||
this.#strategies.push(new PossiblePeakStrategy());
|
||||
this.#strategies.push(new AvgMinMaxStrategy());
|
||||
this.#strategies.push(new AvgMinMaxStrategy2());
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@ -97,7 +97,7 @@ export default class StatisticWorker extends AbstractWorker {
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
const timestamp = Date.now()
|
||||
const peaks = assetData.getPeakDetector().peaks;
|
||||
this.#peackCount = peaks.length;
|
||||
this.#tradeCount.push([timestamp, lastMinAssetData.getTrades()]);
|
||||
this.#tradeVolume.push([timestamp, lastMinAssetData.getVolume()]);
|
||||
this.#price.push([timestamp, lastMinAssetData.getHigh(), lastMinAssetData.getLow(), (lastMinAssetData.getHigh() + lastMinAssetData.getLow()) / 2]);
|
||||
this.#tradeCount.push([timestamp, lastMinAssetData.tradeCount]);
|
||||
this.#tradeVolume.push([timestamp, lastMinAssetData.tradeVolume]);
|
||||
this.#price.push([timestamp, lastMinAssetData.maxPrice, lastMinAssetData.minPrice, lastMinAssetData.avgPrice]);
|
||||
this.#peakEnd.push([timestamp, false]);
|
||||
this.#peakStart.push([timestamp, false]);
|
||||
this.#buys.push([timestamp, this.#buyCount]);
|
||||
@ -240,7 +241,7 @@ export default class StatisticWorker extends AbstractWorker {
|
||||
|
||||
/**
|
||||
* @param {string} objString
|
||||
* @returns {AbstractWorker}
|
||||
* @returns {StatisticWorker2}
|
||||
*/
|
||||
static fromJson(objString) {
|
||||
return super.fromJson(objString, new StatisticWorker());
|
||||
|
||||
@ -5,7 +5,6 @@ import TradingPair from "../apiwrapper/assets/TradingPair.js";
|
||||
import Transaction from "../apiwrapper/transaction/Transaction.js";
|
||||
import TransactionSettings from "../apiwrapper/transaction/TransactionSettings.js";
|
||||
import BotConfig from "../tradingbot/config/BotConfig.js";
|
||||
import AssetDataCollectionConfig from "../tradingbot/data/asset/AssetDataCollectionConfig.js";
|
||||
import AbstractStrategy from "../tradingbot/strategy/AbstractStrategy.js";
|
||||
import AvgMinMaxStrategy from "../tradingbot/strategy/AvgMinMaxStrategy.js";
|
||||
import PossiblePeakStrategy from "../tradingbot/strategy/PossiblePeakStrategy.js";
|
||||
@ -27,7 +26,6 @@ export default class Serializables {
|
||||
['AbstractWorker', AbstractWorker],
|
||||
['StatisticWorker', StatisticWorker],
|
||||
['DefaultWorker', DefaultWorker],
|
||||
['AssetDataCollectionConfig', AssetDataCollectionConfig],
|
||||
['AbstractStrategy', AbstractStrategy],
|
||||
['TestStrategy', TestStrategy],
|
||||
['Simple24hStrategy', Simple24hStrategy],
|
||||
|
||||
@ -85,7 +85,7 @@ export default class RestClient {
|
||||
const st = starttime != null ? starttime : -1;
|
||||
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 result = [];
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user