Фикс пропажи точек
parent
ac9cb53525
commit
a0aaff5360
|
@ -3,6 +3,7 @@
|
|||
public enum TimeWindowCacheType
|
||||
{
|
||||
None = 0,
|
||||
_20_Seconds = 2001,
|
||||
_1_Minute = 1,
|
||||
_5_Minutes = 2,
|
||||
_15_Minutes = 15,
|
||||
|
|
|
@ -51,6 +51,10 @@ namespace KLHZ.Trader.Core.Math.Declisions.Dtos
|
|||
{
|
||||
return TimeSpan.FromMinutes(15);
|
||||
}
|
||||
case TimeWindowCacheType._20_Seconds:
|
||||
{
|
||||
return TimeSpan.FromSeconds(20);
|
||||
}
|
||||
default:
|
||||
{
|
||||
return TimeSpan.FromMinutes(1);
|
||||
|
|
|
@ -50,6 +50,7 @@ namespace KLHZ.Trader.Core.Math.Declisions.Services.Cache
|
|||
private readonly object _locker = new();
|
||||
private readonly decimal[] Prices = new decimal[_arrayMaxLength];
|
||||
private readonly DateTime[] Timestamps = new DateTime[_arrayMaxLength];
|
||||
private readonly ConcurrentDictionary<string, TimeWindowCacheItem> _20_secTimeWindows = new();
|
||||
private readonly ConcurrentDictionary<string, TimeWindowCacheItem> _1_minTimeWindows = new();
|
||||
private readonly ConcurrentDictionary<string, TimeWindowCacheItem> _5_minTimeWindows = new();
|
||||
private readonly ConcurrentDictionary<string, TimeWindowCacheItem> _15_minTimeWindows = new();
|
||||
|
@ -93,6 +94,10 @@ namespace KLHZ.Trader.Core.Math.Declisions.Services.Cache
|
|||
{
|
||||
return _15_minTimeWindows;
|
||||
}
|
||||
case TimeWindowCacheType._20_Seconds:
|
||||
{
|
||||
return _20_secTimeWindows;
|
||||
}
|
||||
default:
|
||||
{
|
||||
return _1_minTimeWindows; ;
|
||||
|
|
|
@ -144,7 +144,8 @@ namespace KLHZ.Trader.Core.Math.Declisions.Utils
|
|||
s = shift;
|
||||
var i2 = size - 1 - shift;
|
||||
var i1 = size - 2 - shift;
|
||||
|
||||
var debugT = timestamps.Reverse().ToArray();
|
||||
var debugV = prices.Reverse().ToArray();
|
||||
var twavs = CalcTimeWindowAverageValue(timestamps, prices, smallWindow, shift);
|
||||
var twavb = CalcTimeWindowAverageValue(timestamps, prices, bigWindow, shift);
|
||||
pricesForFinalComparison[i2] = prices[prices.Length - 1 - shift];
|
||||
|
@ -182,7 +183,8 @@ namespace KLHZ.Trader.Core.Math.Declisions.Utils
|
|||
// если фильтрация окном 15 наползает на окно 120 сверху, потенциальное время закрытия лонга и возможно открытия шорта
|
||||
if (twavss[size - 1] <= twavbs[size - 1] && twavss[size - 2] > twavbs[size - 2])
|
||||
{
|
||||
//if (pricesForFinalComparison[crossings[0]] - pricesForFinalComparison[crossings[1]] >= uptrendEndingDetectionMeanfullStep)
|
||||
var d = pricesForFinalComparison[crossings[0]] - pricesForFinalComparison[crossings[1]];
|
||||
//if (d >= uptrendEndingDetectionMeanfullStep)
|
||||
{
|
||||
res |= TradingEvent.UptrendEnd;
|
||||
}
|
||||
|
@ -191,7 +193,8 @@ namespace KLHZ.Trader.Core.Math.Declisions.Utils
|
|||
// если фильтрация окном 120 наползает на окно 15 сверху, потенциальное время открытия лонга и закрытия шорта
|
||||
if (twavss[size - 1] >= twavbs[size - 1] && twavss[size - 2] < twavbs[size - 2])
|
||||
{
|
||||
//if (pricesForFinalComparison[crossings[0]] - pricesForFinalComparison[crossings[1]] <= uptrendStartingDetectionMeanfullStep)
|
||||
var d = pricesForFinalComparison[crossings[0]] - pricesForFinalComparison[crossings[1]];
|
||||
//if (d <= -uptrendStartingDetectionMeanfullStep)
|
||||
{
|
||||
res |= TradingEvent.UptrendStart;
|
||||
}
|
||||
|
|
|
@ -156,7 +156,7 @@ namespace KLHZ.Trader.Core.Exchange.Services
|
|||
Count = response.Trade.Quantity,
|
||||
};
|
||||
|
||||
await _tradeDataProvider.AddData(message, TimeSpan.FromHours(7));
|
||||
//await _tradeDataProvider.AddData(message, TimeSpan.FromHours(7));
|
||||
await _eventBus.Broadcast(message);
|
||||
|
||||
var exchangeState = ExchangeScheduler.GetCurrentState();
|
||||
|
|
|
@ -19,6 +19,7 @@ using Microsoft.Extensions.Logging;
|
|||
using Microsoft.Extensions.Options;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Immutable;
|
||||
using System.Linq;
|
||||
using System.Security.Cryptography;
|
||||
using System.Threading.Channels;
|
||||
using Tinkoff.InvestApi;
|
||||
|
@ -106,6 +107,26 @@ namespace KLHZ.Trader.Core.Exchange.Services
|
|||
return data2;
|
||||
}
|
||||
|
||||
private async ValueTask<(decimal smallWindow, decimal bigWindow)> GetWindowsSizes(INewPrice message)
|
||||
{
|
||||
var fftFull = await _tradeDataProvider.GetFFtResult(message.Figi + "_full");
|
||||
if (!fftFull.IsEmpty)
|
||||
{
|
||||
var harms = fftFull.Harmonics.Skip(1).Take(fftFull.Harmonics.Length - 3).ToArray();
|
||||
var sum = harms.Sum(h => h.Magnitude);
|
||||
var sumtmp = 0f;
|
||||
foreach (var h in harms)
|
||||
{
|
||||
sumtmp += h.Magnitude;
|
||||
if (sumtmp / sum > 0.7f)
|
||||
{
|
||||
return ((decimal)(h.Period.TotalSeconds / 4), (decimal)(h.Period.TotalSeconds));
|
||||
}
|
||||
}
|
||||
}
|
||||
return (30m, 180m);
|
||||
}
|
||||
|
||||
private async ValueTask<ValueAmplitudePosition> CheckHarmonicPosition((DateTime[] timestamps, decimal[] prices, bool isFullIntervalExists) data, INewPrice message)
|
||||
{
|
||||
var currentTime = message.IsHistoricalData ? message.Time : DateTime.UtcNow;
|
||||
|
@ -114,19 +135,20 @@ namespace KLHZ.Trader.Core.Exchange.Services
|
|||
var fftFull = await _tradeDataProvider.GetFFtResult(message.Figi + "_full");
|
||||
//var highFreq = await _tradeDataProvider.GetFFtResult(message.Figi + "_high_freq");
|
||||
//var lowFreq = await _tradeDataProvider.GetFFtResult(message.Figi + "_low_freq");
|
||||
var step = message.IsHistoricalData ? 5 : 5;
|
||||
var step = message.IsHistoricalData ? 40 : 5;
|
||||
if (fft.IsEmpty || (currentTime - fft.LastTime).TotalSeconds > step)
|
||||
{
|
||||
if (data.isFullIntervalExists)
|
||||
{
|
||||
var interpolatedData = SignalProcessing.InterpolateData(data.timestamps, data.prices, TimeSpan.FromSeconds(5));
|
||||
fftFull = FFT.Analyze(interpolatedData.timestamps, interpolatedData.values, message.Figi+"_full", TimeSpan.FromSeconds(120), TimeSpan.FromHours(24));
|
||||
fft = FFT.ReAnalyze(fftFull, message.Figi, TimeSpan.FromMinutes(3), TimeSpan.FromMinutes(40));
|
||||
fftFull = FFT.Analyze(interpolatedData.timestamps, interpolatedData.values, message.Figi+"_full", TimeSpan.FromSeconds(30), TimeSpan.FromHours(24));
|
||||
|
||||
fft = FFT.ReAnalyze(fftFull, message.Figi, TimeSpan.FromMinutes(10), TimeSpan.FromMinutes(60));
|
||||
//highFreq = FFT.ReAnalyze(fftFull, message.Figi + "_low_freq", TimeSpan.FromMinutes(20), TimeSpan.FromMinutes(60));
|
||||
//lowFreq = FFT.ReAnalyze(fftFull, message.Figi + "_high_freq", TimeSpan.FromMinutes(3), TimeSpan.FromMinutes(20));
|
||||
|
||||
await _tradeDataProvider.SetFFtResult(fft);
|
||||
//await _tradeDataProvider.SetFFtResult(fftFull);
|
||||
await _tradeDataProvider.SetFFtResult(fftFull);
|
||||
//await _tradeDataProvider.SetFFtResult(lowFreq);
|
||||
//await _tradeDataProvider.SetFFtResult(highFreq);
|
||||
|
||||
|
@ -237,13 +259,9 @@ namespace KLHZ.Trader.Core.Exchange.Services
|
|||
var changeMods = GetInitDict(0);
|
||||
try
|
||||
{
|
||||
if (message.IsHistoricalData)
|
||||
{
|
||||
await _tradeDataProvider.AddData(message, TimeSpan.FromHours(6));
|
||||
}
|
||||
#region Ускорение обработки исторических данных при отладке
|
||||
if (message.Direction == 1)
|
||||
{
|
||||
{
|
||||
if (!pricesCache1.TryGetValue(message.Figi, out var list))
|
||||
{
|
||||
list = new List<INewPrice>();
|
||||
|
@ -273,6 +291,7 @@ namespace KLHZ.Trader.Core.Exchange.Services
|
|||
}
|
||||
if (message.Direction == 2)
|
||||
{
|
||||
|
||||
if (!pricesCache2.TryGetValue(message.Figi, out var list))
|
||||
{
|
||||
list = new List<INewPrice>();
|
||||
|
@ -301,6 +320,9 @@ namespace KLHZ.Trader.Core.Exchange.Services
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
#endregion
|
||||
|
||||
#region Подсчёт торгового баланса по сберу и IMOEXF
|
||||
|
@ -308,6 +330,11 @@ namespace KLHZ.Trader.Core.Exchange.Services
|
|||
{
|
||||
if (message.Direction == 1)
|
||||
{
|
||||
await _tradeDataProvider.AddDataTo20SecondsWindowCache(message.Figi, "1", new Contracts.Declisions.Dtos.CachedValue()
|
||||
{
|
||||
Time = message.Time,
|
||||
Value = message.Count
|
||||
});
|
||||
await _tradeDataProvider.AddDataTo5MinuteWindowCache(message.Figi, Constants._5minBuyCacheKey, new Contracts.Declisions.Dtos.CachedValue()
|
||||
{
|
||||
Time = message.Time,
|
||||
|
@ -331,7 +358,76 @@ namespace KLHZ.Trader.Core.Exchange.Services
|
|||
Time = message.Time,
|
||||
Value = (decimal)message.Count
|
||||
});
|
||||
await _tradeDataProvider.AddDataTo20SecondsWindowCache(message.Figi, "2", new Contracts.Declisions.Dtos.CachedValue()
|
||||
{
|
||||
Time = message.Time,
|
||||
Value = message.Count
|
||||
});
|
||||
}
|
||||
|
||||
var buys = await _tradeDataProvider.GetDataFrom20SecondsWindowCache(message.Figi, "1");
|
||||
var sells = await _tradeDataProvider.GetDataFrom20SecondsWindowCache(message.Figi, "2");
|
||||
|
||||
|
||||
var buysSpeed = buys.Sum(p => p.Value) / 20;
|
||||
var sellsSpeed = sells.Sum(p => p.Value) / 20;
|
||||
|
||||
var orderBook = _tradeDataProvider.Orderbooks[message.Figi];
|
||||
if (orderBook.Asks.Length>3 && orderBook.Bids.Length>3)
|
||||
{
|
||||
var asks = (decimal)(orderBook.Asks[0].Count + orderBook.Asks[1].Count + orderBook.Asks[2].Count);
|
||||
//var asks = (decimal)(orderBook.Asks[0].Count + orderBook.Asks[1].Count + orderBook.Asks[2].Count + orderBook.Asks[3].Count);
|
||||
var bids = (decimal)(orderBook.Bids[0].Count + orderBook.Bids[1].Count + orderBook.Bids[2].Count);
|
||||
//var bids = (decimal)(orderBook.Bids[0].Count + orderBook.Bids[1].Count + orderBook.Bids[2].Count + orderBook.Bids[3].Count);
|
||||
|
||||
if (buysSpeed > 0 && sellsSpeed > 0)
|
||||
{
|
||||
await LogPrice(message, "speed_relation", (sellsSpeed / (sellsSpeed + buysSpeed)));
|
||||
}
|
||||
|
||||
//var diff = buysSpeed - sellsSpeed;
|
||||
//await LogPrice(message, "speed_diff", diff);
|
||||
//await LogPrice(message, "stabling", (asks+bids)/(sellsSpeed+buysSpeed));
|
||||
|
||||
//if (buysSpeed > 0)
|
||||
//{
|
||||
// var asksLifetime = asks / buysSpeed;
|
||||
// if (asksLifetime > 600) asksLifetime = 600;
|
||||
// var asksLifetime2 = diff > 0?System.Math.Abs( asks / diff):0;
|
||||
// await LogPrice(message, "asks_lifetime", asksLifetime);
|
||||
// await LogPrice(message, "asks_lifetime2", asksLifetime2);
|
||||
// await LogPrice(message, "asks_lifetime2", asksLifetime2);
|
||||
// await LogPrice(message, "buys_speed", buysSpeed);
|
||||
//}
|
||||
|
||||
|
||||
//if (sellsSpeed > 0)
|
||||
//{
|
||||
// var bidsLifetime = bids / sellsSpeed;
|
||||
// if (bidsLifetime > 600) bidsLifetime = 600;
|
||||
// var bidsLifetime2 = diff < 0 ? System.Math.Abs(bids / diff) : 0;
|
||||
// await LogPrice(message, "bids_lifetime", bidsLifetime);
|
||||
// await LogPrice(message, "bids_lifetime2", System.Math.Abs(bidsLifetime2));
|
||||
// await LogPrice(message, "sells_speed", sellsSpeed);
|
||||
//}
|
||||
|
||||
|
||||
var buys5min = await _tradeDataProvider.GetDataFrom5MinuteWindowCache(message.Figi, Constants._5minBuyCacheKey);
|
||||
var sells5min = await _tradeDataProvider.GetDataFrom5MinuteWindowCache(message.Figi, Constants._5minSellCacheKey);
|
||||
var buysSpeed5min = buys5min.Sum(p => p.Value) / 300;
|
||||
var sellsSpeed5min = sells5min.Sum(p => p.Value) / 300;
|
||||
var diff5min = buysSpeed5min - sellsSpeed5min;
|
||||
await LogPrice(message, "speed_diff_5min", diff5min);
|
||||
|
||||
//var buys1min = await _tradeDataProvider.GetDataFrom1MinuteWindowCache(message.Figi, Constants._1minBuyCacheKey);
|
||||
//var sells1min = await _tradeDataProvider.GetDataFrom1MinuteWindowCache(message.Figi, Constants._1minSellCacheKey);
|
||||
//var buysSpeed1min = buys1min.Sum(p => p.Value) / 60;
|
||||
//var sellsSpeed1min = sells1min.Sum(p => p.Value) / 60;
|
||||
//var diff1min = buysSpeed1min - sellsSpeed1min;
|
||||
//await LogPrice(message, "speed_diff_1min", diff1min);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
#endregion
|
||||
if (_tradingInstrumentsFigis.Contains(message.Figi) && message.Figi == "FUTIMOEXF000" && message.Direction == 1)
|
||||
|
@ -413,6 +509,7 @@ namespace KLHZ.Trader.Core.Exchange.Services
|
|||
try
|
||||
{
|
||||
if (message.Direction != 1) continue;
|
||||
await _tradeDataProvider.AddData(message);
|
||||
ProcessStops(message, currentTime);
|
||||
var windowMaxSize = 2000;
|
||||
var data = await _tradeDataProvider.GetData(message.Figi, windowMaxSize);
|
||||
|
@ -433,6 +530,35 @@ namespace KLHZ.Trader.Core.Exchange.Services
|
|||
}
|
||||
}
|
||||
|
||||
private async Task<ImmutableDictionary<TradingEvent, decimal>> GetSpeedResultantMods(INewPrice message)
|
||||
{
|
||||
var res = GetInitDict(1);
|
||||
var buys5min = await _tradeDataProvider.GetDataFrom5MinuteWindowCache(message.Figi, Constants._5minBuyCacheKey);
|
||||
var sells5min = await _tradeDataProvider.GetDataFrom5MinuteWindowCache(message.Figi, Constants._5minSellCacheKey);
|
||||
var buysSpeed5min = buys5min.Sum(p => p.Value) / 300;
|
||||
var sellsSpeed5min = sells5min.Sum(p => p.Value) / 300;
|
||||
var diff5min = buysSpeed5min - sellsSpeed5min;
|
||||
await LogPrice(message, "speed_diff_5min", diff5min);
|
||||
|
||||
if (diff5min < 0)
|
||||
{
|
||||
res[TradingEvent.UptrendStart] = Constants.BlockingCoefficient;
|
||||
}
|
||||
if (diff5min > 0)
|
||||
{
|
||||
res[TradingEvent.DowntrendStart] = Constants.BlockingCoefficient;
|
||||
}
|
||||
if (diff5min > 6)
|
||||
{
|
||||
res[TradingEvent.UptrendEnd] = Constants.BlockingCoefficient;
|
||||
}
|
||||
if (diff5min < -6)
|
||||
{
|
||||
res[TradingEvent.DowntrendEnd] = Constants.BlockingCoefficient;
|
||||
}
|
||||
return res.ToImmutableDictionary();
|
||||
}
|
||||
|
||||
private async Task<Dictionary<TradingEvent, decimal>> GetWindowAverageStartData((DateTime[] timestamps, decimal[] prices) data, int smallWindow, int bigWindow,
|
||||
INewPrice message, int windowMaxSize, decimal uptrendStartingDetectionMeanfullStep = 0m, decimal uptrendEndingDetectionMeanfullStep = 3m)
|
||||
{
|
||||
|
@ -570,33 +696,34 @@ INewPrice message, int windowMaxSize, decimal uptrendStartingDetectionMeanfullSt
|
|||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var windows = await GetWindowsSizes(message);
|
||||
//var resTask1 = GetWindowAverageStartData(data, 30, 180, message, windowMaxSize, -2m, 2m,3);
|
||||
var resTask1 = GetWindowAverageStartData(data, 30, 180, message, windowMaxSize, 0m, 0.5m);
|
||||
//var resTask3 = GetWindowAverageStartData(data, 30, 180, message, windowMaxSize, 0, 0,0.7m);
|
||||
var resTask1 = GetWindowAverageStartData(data, (int)windows.smallWindow, (int)windows.bigWindow, message, windowMaxSize, -0.5m, 0.5m);
|
||||
////var resTask3 = GetWindowAverageStartData(data, 30, 180, message, windowMaxSize, 0, 0,0.7m);
|
||||
var getFFTModsTask = GetFFTMods(message);
|
||||
var getLocalTrendsModsTask = GetLocalTrendsMods(data, message);
|
||||
//var getAreasModsTask = GetAreasMods(data, message);
|
||||
var getSellsDiffsModsTask = GetSellsDiffsMods(message);
|
||||
var getTradingModeModsTask = GetTradingModeMods(message);
|
||||
var getSpeedResultantModsTask = GetSpeedResultantMods(message);
|
||||
|
||||
await Task.WhenAll(resTask1, getFFTModsTask, getSellsDiffsModsTask, getTradingModeModsTask, getLocalTrendsModsTask);
|
||||
await Task.WhenAll(resTask1, getFFTModsTask, getSellsDiffsModsTask, getTradingModeModsTask, getLocalTrendsModsTask, getSpeedResultantModsTask);
|
||||
//var assetType = _tradeDataProvider.GetAssetTypeByFigi(message.Figi);
|
||||
//if (resTask1.Result[TradingEvent.UptrendStart] >= 1)
|
||||
//{
|
||||
|
||||
//}
|
||||
|
||||
var result = getLocalTrendsModsTask.Result;
|
||||
var result = resTask1.Result;
|
||||
|
||||
//result = MergeResults(result, resTask2.Result.ToImmutableDictionary());
|
||||
//result = MergeResults(result, resTask3.Result.ToImmutableDictionary());
|
||||
//result = MergeResultsMax(result, changeModeData);
|
||||
//result = MergeResultsMax(result, getLocalTrendsModsTask.Result);
|
||||
//result = MergeResultsMult(result, getFFTModsTask.Result);
|
||||
////////result = MergeResults(result, getAreasModsTask.Result);
|
||||
//result = MergeResultsMult(result, getSellsDiffsModsTask.Result);
|
||||
|
||||
//result = MergeResultsMult(result, getTradingModeModsTask.Result);
|
||||
//result = MergeResultsMult(result, getSpeedResultantModsTask.Result);
|
||||
|
||||
if (result[TradingEvent.UptrendStart] >= Constants.UppingCoefficient
|
||||
&& !LongOpeningStops.ContainsKey(message.Figi)
|
||||
|
@ -614,12 +741,11 @@ INewPrice message, int windowMaxSize, decimal uptrendStartingDetectionMeanfullSt
|
|||
await OpenPositions(accounts, message, PositionType.Long, stops.stopLoss, stops.takeProfit, 1);
|
||||
LongOpeningStops[message.Figi] = DateTime.UtcNow.AddMinutes(1);
|
||||
}
|
||||
|
||||
await LogDeclision(DeclisionTradeAction.OpenLong, message);
|
||||
await LogDeclision(DeclisionTradeAction.OpenLong, message.Value, message.Time.AddMilliseconds(RandomNumberGenerator.GetInt32(-100, 100)), message);
|
||||
await LogDeclision(DeclisionTradeAction.ResetStopsLong, message.Value + stops.takeProfit, message.Time.AddMilliseconds(-RandomNumberGenerator.GetInt32(300, 1000)), message);
|
||||
await LogDeclision(DeclisionTradeAction.ResetStopsLong, message.Value - stops.stopLoss, message.Time.AddMilliseconds(RandomNumberGenerator.GetInt32(300, 1000)), message);
|
||||
}
|
||||
if (result[TradingEvent.DowntrendStart] > Constants.UppingCoefficient
|
||||
if (result[TradingEvent.DowntrendStart] >= Constants.UppingCoefficient
|
||||
&& !ShortOpeningStops.ContainsKey(message.Figi)
|
||||
&& state == ExchangeState.Open
|
||||
)
|
||||
|
@ -636,11 +762,11 @@ INewPrice message, int windowMaxSize, decimal uptrendStartingDetectionMeanfullSt
|
|||
ShortOpeningStops[message.Figi] = DateTime.UtcNow.AddMinutes(1);
|
||||
}
|
||||
|
||||
await LogDeclision(DeclisionTradeAction.OpenShort, message);
|
||||
await LogDeclision(DeclisionTradeAction.OpenShort, message.Value, message.Time.AddMilliseconds(RandomNumberGenerator.GetInt32(-100, 100)), message);
|
||||
await LogDeclision(DeclisionTradeAction.ResetStopsShort, message.Value - stops.takeProfit, message.Time.AddMilliseconds(-RandomNumberGenerator.GetInt32(300, 1000)), message);
|
||||
await LogDeclision(DeclisionTradeAction.ResetStopsShort, message.Value + stops.stopLoss, message.Time.AddMilliseconds(RandomNumberGenerator.GetInt32(300, 1000)), message);
|
||||
}
|
||||
if (result[TradingEvent.UptrendEnd] > Constants.UppingCoefficient)
|
||||
if (result[TradingEvent.UptrendEnd] >= Constants.UppingCoefficient)
|
||||
{
|
||||
if (!message.IsHistoricalData && BotModeSwitcher.CanSell())
|
||||
{
|
||||
|
@ -650,10 +776,11 @@ INewPrice message, int windowMaxSize, decimal uptrendStartingDetectionMeanfullSt
|
|||
.ToArray();
|
||||
await ClosePositions(assetsForClose, message);
|
||||
}
|
||||
await LogDeclision(DeclisionTradeAction.CloseLong, message);
|
||||
await LogDeclision(DeclisionTradeAction.CloseLong, message.Value, message.Time.AddMilliseconds(RandomNumberGenerator.GetInt32(-100, 100)), message);
|
||||
|
||||
}
|
||||
|
||||
if (result[TradingEvent.DowntrendEnd] > Constants.UppingCoefficient)
|
||||
if (result[TradingEvent.DowntrendEnd] >= Constants.UppingCoefficient)
|
||||
{
|
||||
if (!message.IsHistoricalData && BotModeSwitcher.CanPurchase())
|
||||
{
|
||||
|
@ -663,7 +790,8 @@ INewPrice message, int windowMaxSize, decimal uptrendStartingDetectionMeanfullSt
|
|||
.ToArray();
|
||||
await ClosePositions(assetsForClose, message);
|
||||
}
|
||||
await LogDeclision(DeclisionTradeAction.CloseShort, message);
|
||||
await LogDeclision(DeclisionTradeAction.CloseShort, message.Value, message.Time.AddMilliseconds(RandomNumberGenerator.GetInt32(-100, 100)), message);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -773,19 +901,9 @@ INewPrice message, int windowMaxSize, decimal uptrendStartingDetectionMeanfullSt
|
|||
private async Task<TradingMode> CalcTradingMode(string figi)
|
||||
{
|
||||
var res = TradingMode.None;
|
||||
var largeData = await _tradeDataProvider.GetData(figi, TimeSpan.FromMinutes(90));
|
||||
var smallData = await _tradeDataProvider.GetData(figi, TimeSpan.FromMinutes(15));
|
||||
var largeData = await _tradeDataProvider.GetData(figi, TimeSpan.FromMinutes(45));
|
||||
var smallData = await _tradeDataProvider.GetData(figi, TimeSpan.FromMinutes(10));
|
||||
|
||||
if (!largeData.isFullIntervalExists && smallData.isFullIntervalExists)
|
||||
{
|
||||
largeData = await _tradeDataProvider.GetData(figi, TimeSpan.FromMinutes(45));
|
||||
smallData = await _tradeDataProvider.GetData(figi, TimeSpan.FromMinutes(10));
|
||||
}
|
||||
if (!largeData.isFullIntervalExists && smallData.isFullIntervalExists)
|
||||
{
|
||||
largeData = await _tradeDataProvider.GetData(figi, TimeSpan.FromMinutes(15));
|
||||
smallData = await _tradeDataProvider.GetData(figi, TimeSpan.FromMinutes(7));
|
||||
}
|
||||
if (largeData.isFullIntervalExists && smallData.isFullIntervalExists)
|
||||
{
|
||||
if (LocalTrends.TryCalcTrendDiff(largeData.timestamps, largeData.prices, out var largeDataRes)
|
||||
|
@ -879,14 +997,14 @@ INewPrice message, int windowMaxSize, decimal uptrendStartingDetectionMeanfullSt
|
|||
//res[TradingEvent.UptrendStart] = Constants.UppingCoefficient;
|
||||
res[TradingEvent.DowntrendEnd] = Constants.UppingCoefficient;
|
||||
//res[TradingEvent.UptrendEnd] = Constants.LowingCoefficient;
|
||||
res[TradingEvent.DowntrendStart] = Constants.BlockingCoefficient;
|
||||
res[TradingEvent.DowntrendStart] = Constants.LowingCoefficient;
|
||||
}
|
||||
if (position == ValueAmplitudePosition.UpperThen30Decil)
|
||||
{
|
||||
res[TradingEvent.UptrendStart] = Constants.BlockingCoefficient;
|
||||
res[TradingEvent.UptrendStart] = Constants.LowingCoefficient;
|
||||
//res[TradingEvent.DowntrendEnd] = Constants.LowingCoefficient;
|
||||
//res[TradingEvent.UptrendEnd] = Constants.UppingCoefficient;
|
||||
res[TradingEvent.DowntrendStart] = Constants.UppingCoefficient;
|
||||
res[TradingEvent.DowntrendEnd] = Constants.UppingCoefficient;
|
||||
}
|
||||
return res.ToImmutableDictionary();
|
||||
}
|
||||
|
|
|
@ -29,6 +29,7 @@ namespace KLHZ.Trader.Core.Exchange.Services
|
|||
private readonly ILogger<TraderDataProvider> _logger;
|
||||
private readonly string[] _instrumentsFigis = [];
|
||||
|
||||
public readonly ConcurrentDictionary<string, IOrderbook> Orderbooks = new();
|
||||
private readonly ConcurrentDictionary<string, FFTAnalyzeResult> _fftResults = new();
|
||||
private readonly ConcurrentDictionary<string, string> _tickersCache = new();
|
||||
private readonly ConcurrentDictionary<string, AssetType> _assetTypesCache = new();
|
||||
|
@ -125,6 +126,16 @@ namespace KLHZ.Trader.Core.Exchange.Services
|
|||
await _historyCash[figi].AddDataToTimeWindowCache(key, data, TimeWindowCacheType._1_Minute);
|
||||
}
|
||||
|
||||
public async ValueTask AddDataTo20SecondsWindowCache(string figi, string key, CachedValue data)
|
||||
{
|
||||
if (!_historyCash.TryGetValue(figi, out var unit))
|
||||
{
|
||||
unit = new PriceHistoryCacheUnit2(figi);
|
||||
_historyCash.TryAdd(figi, unit);
|
||||
}
|
||||
await _historyCash[figi].AddDataToTimeWindowCache(key, data, TimeWindowCacheType._20_Seconds);
|
||||
}
|
||||
|
||||
public async ValueTask AddDataTo5MinuteWindowCache(string figi, string key, CachedValue data)
|
||||
{
|
||||
if (!_historyCash.TryGetValue(figi, out var unit))
|
||||
|
@ -135,6 +146,15 @@ namespace KLHZ.Trader.Core.Exchange.Services
|
|||
await _historyCash[figi].AddDataToTimeWindowCache(key, data, TimeWindowCacheType._5_Minutes);
|
||||
}
|
||||
|
||||
public ValueTask<CachedValue[]> GetDataFrom20SecondsWindowCache(string figi, string key)
|
||||
{
|
||||
if (_historyCash.TryGetValue(figi, out var cahcheItem))
|
||||
{
|
||||
return cahcheItem.GetDataFromTimeWindowCache(key, TimeWindowCacheType._20_Seconds);
|
||||
}
|
||||
return ValueTask.FromResult(Array.Empty<CachedValue>());
|
||||
}
|
||||
|
||||
public ValueTask<CachedValue[]> GetDataFrom1MinuteWindowCache(string figi, string key)
|
||||
{
|
||||
if (_historyCash.TryGetValue(figi, out var cahcheItem))
|
||||
|
@ -160,7 +180,7 @@ namespace KLHZ.Trader.Core.Exchange.Services
|
|||
unit = new PriceHistoryCacheUnit2(orderbook.Figi);
|
||||
_historyCash.TryAdd(orderbook.Figi, unit);
|
||||
}
|
||||
|
||||
Orderbooks[orderbook.Figi] = orderbook;
|
||||
await unit.AddOrderbook(orderbook);
|
||||
}
|
||||
|
||||
|
|
|
@ -4,7 +4,7 @@ namespace KLHZ.Trader.Core.Exchange.Utils
|
|||
{
|
||||
internal static class ExchangeScheduler
|
||||
{
|
||||
private readonly static TimeOnly _openTimeMain = new(6, 10);
|
||||
private readonly static TimeOnly _openTimeMain = new(6, 0);
|
||||
private readonly static TimeOnly _closeTimeMain = new(20, 45);
|
||||
|
||||
private readonly static TimeOnly _openTimeHoliday = new(7, 10);
|
||||
|
|
|
@ -1,12 +1,17 @@
|
|||
using Grpc.Core;
|
||||
using KLHZ.Trader.Core.Contracts.Messaging.Dtos;
|
||||
using KLHZ.Trader.Core.Contracts.Messaging.Dtos.Interfaces;
|
||||
using KLHZ.Trader.Core.Contracts.Messaging.Interfaces;
|
||||
using KLHZ.Trader.Core.DataLayer;
|
||||
using KLHZ.Trader.Core.DataLayer.Entities.Orders;
|
||||
using KLHZ.Trader.Core.DataLayer.Entities.Prices;
|
||||
using KLHZ.Trader.Core.Exchange.Services;
|
||||
using KLHZ.Trader.Core.Math.Declisions.Utils;
|
||||
using KLHZ.Trader.Service.Models;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Telegram.Bot.Types;
|
||||
using Tinkoff.InvestApi.V1;
|
||||
|
||||
namespace KLHZ.Trader.Service.Controllers
|
||||
{
|
||||
|
@ -39,26 +44,184 @@ namespace KLHZ.Trader.Service.Controllers
|
|||
//var time2 = DateTime.UtcNow.AddMinutes(18);
|
||||
using var context1 = await _dbContextFactory.CreateDbContextAsync();
|
||||
context1.ChangeTracker.QueryTrackingBehavior = QueryTrackingBehavior.NoTracking;
|
||||
var data = await context1.PriceChanges
|
||||
.Where(c => (c.Figi == figi1 || c.Figi == figi2) && c.Time >= time1)
|
||||
.OrderBy(c => c.Time)
|
||||
.Select(c => new NewPriceMessage()
|
||||
{
|
||||
Figi = c.Figi,
|
||||
Ticker = c.Ticker,
|
||||
Time = c.Time,
|
||||
Value = c.Value,
|
||||
IsHistoricalData = true,
|
||||
Direction = c.Direction,
|
||||
Count = c.Count,
|
||||
})
|
||||
.ToArrayAsync();
|
||||
|
||||
|
||||
foreach (var mess in data)
|
||||
|
||||
while (time1 < DateTime.UtcNow)
|
||||
{
|
||||
await _dataBus.Broadcast(mess);
|
||||
var data = new List<TimeSeriesData>();
|
||||
var data2 = new List<TimeSeriesData>();
|
||||
var time2 = time1.AddHours(1);
|
||||
var orderbooks = await context1.OrderbookItems
|
||||
.Where(oi => (oi.Figi == figi1 || oi.Figi == figi2) && oi.Time >= time1 && oi.Time<time2)
|
||||
.OrderBy(c => c.Time)
|
||||
.ToArrayAsync();
|
||||
var prices = await context1.PriceChanges
|
||||
.Where(c => (c.Figi == figi1 || c.Figi == figi2) && c.Time >= time1 && c.Time < time2)
|
||||
.OrderBy(c => c.Time)
|
||||
.Select(c => new NewPriceMessage()
|
||||
{
|
||||
Figi = c.Figi,
|
||||
Ticker = c.Ticker,
|
||||
Time = c.Time,
|
||||
Value = c.Value,
|
||||
IsHistoricalData = true,
|
||||
Direction = c.Direction,
|
||||
Count = c.Count,
|
||||
})
|
||||
.ToArrayAsync();
|
||||
|
||||
var lookupImoexf = orderbooks.Where(o=>o.Figi== "FUTIMOEXF000").ToLookup(o => o.Time);
|
||||
var lookupSber = orderbooks.Where(o=>o.Figi== "BBG004730N88").ToLookup(o => o.Time);
|
||||
|
||||
foreach (var item in lookupImoexf)
|
||||
{
|
||||
|
||||
var asks = item
|
||||
.Where(i => i.ItemType == Core.DataLayer.Entities.Orders.Enums.OrderbookItemType.Ask)
|
||||
.OrderBy(o => o.Price)
|
||||
.ToList();
|
||||
var bids = item
|
||||
.Where(i => i.ItemType == Core.DataLayer.Entities.Orders.Enums.OrderbookItemType.Bid)
|
||||
.OrderByDescending(o => o.Price)
|
||||
.ToList();
|
||||
|
||||
var forRemove = new List<OrderbookItem>();
|
||||
if (asks.Count > 4 || bids.Count > 4)
|
||||
{
|
||||
|
||||
}
|
||||
foreach (var bid in bids)
|
||||
{
|
||||
var bids2 = bids.Where(b=>b.Price==bid.Price).ToList();
|
||||
var summCount = bids2.Sum(b => b.Count);
|
||||
var b = bids2.First();
|
||||
b.Count = summCount;
|
||||
bids2.Remove(b);
|
||||
forRemove.AddRange(bids2);
|
||||
}
|
||||
|
||||
foreach (var ask in asks)
|
||||
{
|
||||
var asks2 = asks.Where(b => b.Price == ask.Price).ToList();
|
||||
var summCount = asks2.Sum(b => b.Count);
|
||||
var b = asks2.First();
|
||||
b.Count = summCount;
|
||||
asks2.Remove(b);
|
||||
forRemove.AddRange(asks2);
|
||||
}
|
||||
|
||||
asks.RemoveAll(a => forRemove.Contains(a));
|
||||
bids.RemoveAll(a => forRemove.Contains(a));
|
||||
var orderbook = new NewOrderbookMessage() { Figi = "FUTIMOEXF000", Ticker = "IMOEXF", Asks = asks.ToArray(), Bids = bids.ToArray(), AsksCount = asks.Sum(a => a.Count), BidsCount = bids.Sum(a => a.Count), Time = item.Key };
|
||||
var wrapper = new TimeSeriesData()
|
||||
{
|
||||
Figi = orderbook.Figi,
|
||||
Orderbook = orderbook,
|
||||
Time = item.Key,
|
||||
};
|
||||
data.Add(wrapper);
|
||||
}
|
||||
|
||||
foreach (var item in lookupSber)
|
||||
{
|
||||
var asks = item
|
||||
.Where(i => i.ItemType == Core.DataLayer.Entities.Orders.Enums.OrderbookItemType.Ask)
|
||||
.OrderBy(o => o.Price)
|
||||
.ToList();
|
||||
var bids = item
|
||||
.Where(i => i.ItemType == Core.DataLayer.Entities.Orders.Enums.OrderbookItemType.Bid)
|
||||
.OrderByDescending(o => o.Price)
|
||||
.ToList();
|
||||
var forRemove = new List<OrderbookItem>();
|
||||
if (asks.Count > 4 || bids.Count > 4)
|
||||
{
|
||||
|
||||
}
|
||||
foreach (var bid in bids)
|
||||
{
|
||||
var bids2 = bids.Where(b => b.Price == bid.Price).ToList();
|
||||
var summCount = bids2.Sum(b => b.Count);
|
||||
var b = bids2.First();
|
||||
b.Count = summCount;
|
||||
bids2.Remove(b);
|
||||
forRemove.AddRange(bids2);
|
||||
}
|
||||
|
||||
foreach (var ask in asks)
|
||||
{
|
||||
var asks2 = asks.Where(b => b.Price == ask.Price).ToList();
|
||||
var summCount = asks2.Sum(b => b.Count);
|
||||
var b = asks2.First();
|
||||
b.Count = summCount;
|
||||
asks2.Remove(b);
|
||||
forRemove.AddRange(asks2);
|
||||
}
|
||||
asks.RemoveAll(a => forRemove.Contains(a));
|
||||
bids.RemoveAll(a => forRemove.Contains(a));
|
||||
var orderbook = new NewOrderbookMessage() { Figi = "BBG004730N88", Ticker = "SBER", Asks = asks.ToArray(), Bids = bids.ToArray(), AsksCount = asks.Sum(a => a.Count), BidsCount = bids.Sum(a => a.Count), Time = item.Key };
|
||||
var wrapper = new TimeSeriesData()
|
||||
{
|
||||
Figi = orderbook.Figi,
|
||||
Orderbook = orderbook,
|
||||
Time = item.Key,
|
||||
};
|
||||
data.Add(wrapper);
|
||||
}
|
||||
time1 = time2;
|
||||
|
||||
foreach (var price in prices)
|
||||
{
|
||||
var wrapper = new TimeSeriesData()
|
||||
{
|
||||
Figi = price.Figi,
|
||||
NewPrice = price,
|
||||
Time = price.Time,
|
||||
};
|
||||
data.Add(wrapper);
|
||||
}
|
||||
data = data.OrderBy(d => d.Time).ToList();
|
||||
for(int i = 0; i < data.Count; i++)
|
||||
{
|
||||
if (data[i].NewPrice != null && i>0)
|
||||
{
|
||||
for (int i1=i-1; i1 >=0; i1--)
|
||||
{
|
||||
var ob = data[i1].Orderbook;
|
||||
if (data[i1].Figi == data[i].Figi && ob != null)
|
||||
{
|
||||
var d =new TimeSeriesData()
|
||||
{
|
||||
Figi = ob.Figi,
|
||||
Orderbook = ob,
|
||||
Time = data[i].Time,
|
||||
NewPrice = data[i].NewPrice,
|
||||
};
|
||||
data2.Add(d);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var mess in data2)
|
||||
{
|
||||
if (mess.Orderbook != null)
|
||||
{
|
||||
await _traderDataProvider.AddOrderbook(mess.Orderbook);
|
||||
}
|
||||
if (mess.NewPrice != null)
|
||||
{
|
||||
//await _traderDataProvider.AddData(mess.NewPrice, TimeSpan.FromHours(6));
|
||||
await _dataBus.Broadcast(mess.NewPrice);
|
||||
}
|
||||
}
|
||||
data.Clear();
|
||||
data2.Clear();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
|
|
|
@ -0,0 +1,12 @@
|
|||
using KLHZ.Trader.Core.Contracts.Messaging.Dtos.Interfaces;
|
||||
|
||||
namespace KLHZ.Trader.Service.Models
|
||||
{
|
||||
public class TimeSeriesData
|
||||
{
|
||||
public required string Figi { get; set;}
|
||||
public DateTime Time { get; set; }
|
||||
public INewPrice? NewPrice { get; set; }
|
||||
public IOrderbook? Orderbook { get; set; }
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue