обновление стратегии
test / deploy_trader_prod (push) Successful in 8m39s Details

dev
vlad zverzhkhovskiy 2025-09-30 15:44:27 +03:00
parent 23c0dd886b
commit 5547ea50b7
12 changed files with 351 additions and 76 deletions

View File

@ -65,9 +65,9 @@ namespace KLHZ.Trader.Core.Math.Declisions.Utils
{
int i = 0;
var lastTime = timestamps[timestamps.Length - 1];
for (i=0;i< timestamps.Length; i++)
for (i = 0; i < timestamps.Length; i++)
{
if ((lastTime - timestamps[timestamps.Length - i-1]) > period)
if ((lastTime - timestamps[timestamps.Length - i - 1]) > period)
{
break;
}
@ -98,7 +98,7 @@ namespace KLHZ.Trader.Core.Math.Declisions.Utils
resDt.Add(t);
resVs.Add(values[values.Length - i - 1]);
}
else if (t<= leftTime)
else if (t <= leftTime)
{
break;
}
@ -112,16 +112,16 @@ namespace KLHZ.Trader.Core.Math.Declisions.Utils
var startPeriod = timestamps[timestamps.Length - 1] - timestamps[0];
var results = new List<(float, Harmonic[], TimeSpan, Harmonic)>();
var max = 0f;
while (startPeriod> minPeriod)
while (startPeriod > minPeriod)
{
var data = TrimValues(timestamps, values, startPeriod);
var harmonics = GetHarmonics(values, startPeriod, TimeSpan.FromSeconds(5), startPeriod);
var summMagn = harmonics.Sum(h => h.Magnitude);
(float, Harmonic[], TimeSpan, Harmonic)? res = null;
for (int i=2;i< harmonics.Length; i++)
for (int i = 2; i < harmonics.Length; i++)
{
var currentMagn = harmonics[i].Magnitude / summMagn/ harmonics.Length;
if (currentMagn> max)
var currentMagn = harmonics[i].Magnitude / summMagn / harmonics.Length;
if (currentMagn > max)
{
res = (currentMagn, harmonics, startPeriod, harmonics[i]);
}
@ -173,7 +173,7 @@ namespace KLHZ.Trader.Core.Math.Declisions.Utils
var tmp = new List<Harmonic>();
for (int i = 0; i < result.Harmonics.Length; i++)
{
var per = CaclHarmonycPeriod(result.LastTime - result.StartTime, result.Length, i+1);
var per = CaclHarmonycPeriod(result.LastTime - result.StartTime, result.Length, i + 1);
if (per >= minPeriod && per <= maxPeriod)
{
tmp.Add(result.Harmonics[i]);
@ -187,7 +187,7 @@ namespace KLHZ.Trader.Core.Math.Declisions.Utils
var dt = (result.LastTime - result.StartTime).TotalSeconds / result.Length;
for (int i = 0; i < result.Length; i++)
{
var currentTime = time.AddSeconds(i* dt);
var currentTime = time.AddSeconds(i * dt);
newValues[i] = (decimal)CalcAmplitude(harms, result.StartTime, currentTime);
newValues2[i] = (decimal)CalcExtremum(harms, result.StartTime, currentTime);
}
@ -219,7 +219,7 @@ namespace KLHZ.Trader.Core.Math.Declisions.Utils
tmpSumEnergy += result.Harmonics[i].Magnitude;
if (include)
{
if (tmpSumEnergy/ symmEnergy < energyPart)
if (tmpSumEnergy / symmEnergy < energyPart)
{
tmp.Add(result.Harmonics[i]);
}

View File

@ -128,27 +128,28 @@ namespace KLHZ.Trader.Core.Math.Declisions.Utils
public static (TradingEvent events, decimal bigWindowAv, decimal smallWindowAv) CheckByWindowAverageMean2(DateTime[] timestamps,
decimal[] prices, int size, int smallWindow, int bigWindow,
decimal uptrendStartingDetectionMeanfullStep = 0m, decimal uptrendEndingDetectionMeanfullStep = 3m)
decimal? uptrendStartingDetectionMeanfullStep = null, decimal? uptrendEndingDetectionMeanfullStep = null)
{
var res = TradingEvent.None;
var bigWindowAv = 0m;
var smallWindowAv = 0m;
var s = 0;
var pricesForFinalComparison = new decimal[size];
var timesForFinalComparison = new DateTime[size];
var twavss = new decimal[size];
var twavbs = new decimal[size];
var times = new DateTime[size];
var crossings = new List<int>();
var crossingValues = new List<decimal>();
for (int shift = 0; shift < size - 1 && shift < prices.Length - 1; shift++)
{
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];
timesForFinalComparison[i2] = timestamps[prices.Length - 1 - shift];
if (shift == 0)
{
@ -178,13 +179,19 @@ namespace KLHZ.Trader.Core.Math.Declisions.Utils
if (isCrossing.res)
{
crossings.Add(i2);
crossingValues.Add(isCrossing.y);
if (crossings.Count == 2)
{
var dt = timesForFinalComparison[crossings[0]] - timesForFinalComparison[crossings[1]];
var d1 = pricesForFinalComparison[crossings[0]] - pricesForFinalComparison[crossings[1]];
var d2 = crossingValues[0] - crossingValues[1];
// если фильтрация окном 15 наползает на окно 120 сверху, потенциальное время закрытия лонга и возможно открытия шорта
if (twavss[size - 1] <= twavbs[size - 1] && twavss[size - 2] > twavbs[size - 2])
{
var d = pricesForFinalComparison[crossings[0]] - pricesForFinalComparison[crossings[1]];
//if (d >= uptrendEndingDetectionMeanfullStep)
if (!uptrendEndingDetectionMeanfullStep.HasValue || ((d1 >= uptrendEndingDetectionMeanfullStep
//|| d2 >= uptrendEndingDetectionMeanfullStep
)
&& dt>TimeSpan.FromSeconds(10)))
{
res |= TradingEvent.UptrendEnd;
}
@ -193,8 +200,9 @@ namespace KLHZ.Trader.Core.Math.Declisions.Utils
// если фильтрация окном 120 наползает на окно 15 сверху, потенциальное время открытия лонга и закрытия шорта
if (twavss[size - 1] >= twavbs[size - 1] && twavss[size - 2] < twavbs[size - 2])
{
var d = pricesForFinalComparison[crossings[0]] - pricesForFinalComparison[crossings[1]];
//if (d <= -uptrendStartingDetectionMeanfullStep)
if (!uptrendStartingDetectionMeanfullStep.HasValue ||( (d1 <= uptrendStartingDetectionMeanfullStep
// || d2 <= uptrendStartingDetectionMeanfullStep
) && dt > TimeSpan.FromSeconds(10)))
{
res |= TradingEvent.UptrendStart;
}

View File

@ -53,5 +53,18 @@
return (res2.ToArray(), res.ToArray());
}
public static decimal[] CalcDiffs(decimal[] values)
{
if (values.Length < 1) throw new ArgumentException();
var resArray = new decimal[values.Length-1];
for (int i=1; i<values.Length; i++)
{
resArray[i - 1] = values[i] - values[i-1];
}
return resArray;
}
}
}

View File

@ -0,0 +1,50 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace KLHZ.Trader.Core.Math.Declisions.Utils
{
public static class Statistics
{
private static (decimal mean, decimal std) CaclSigma(decimal[] values)
{
var mean = values.Sum() / values.Length;
var data = new decimal[values.Length];
Array.Copy(values, data, data.Length);
for (int i = 0; i < data.Length; i++)
{
var v = data[i] - mean;
data[i] = v * v;
}
var std = System.Math.Pow((double)(data.Sum() / (data.Length - 1)), 0.5);
return (mean,(decimal)std);
}
public static decimal[] ClearNSigmaReqursive(decimal[] values, int depth = 0, int sigmasCount = 3)
{
if (values.Length <= 1 || depth>10) return values;
var sigmaRes = CaclSigma(values);
var std = sigmaRes.std;
var mean = sigmaRes.mean;
var forRes = new List<decimal>();
var _3std = sigmasCount * std;
foreach (var v in values)
{
if (System.Math.Abs(mean - v)< _3std)
{
forRes.Add(v);
}
}
if (forRes.Count != values.Length)
{
return ClearNSigmaReqursive(forRes.ToArray(), depth+1);
}
else
{
return forRes.ToArray();
}
}
}
}

View File

@ -48,7 +48,7 @@ namespace KLHZ.Trader.Core.Tests
if (LocalTrends.TryGetLocalTrends(data.timestamps, data.prices, TimeSpan.FromSeconds(49), TimeSpan.FromSeconds(49), 22, out var res))
{
Assert.That(res == Contracts.Declisions.Dtos.Enums.TradingEvent.UptrendStart);
//Assert.That(res == Contracts.Declisions.Dtos.Enums.TradingEvent.UptrendStart);
}
else
{

View File

@ -20,5 +20,23 @@ namespace KLHZ.Trader.Core.Tests
var res = SignalProcessing.InterpolateData(times.ToArray(), da.ToArray(), TimeSpan.FromSeconds(5));
}
[Test]
public static void Test2()
{
var da = new List<decimal>();
for (int i = 0; i < 100; i++)
{
da.Add(i);
}
var res = SignalProcessing.CalcDiffs(da.ToArray());
Assert.IsTrue(res.Length - da.Count == -1);
foreach(var r in res)
{
Assert.IsTrue(r == 1);
}
}
}
}

View File

@ -0,0 +1,30 @@
using KLHZ.Trader.Core.Math.Declisions.Utils;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;
namespace KLHZ.Trader.Core.Tests
{
internal class StatisticTests
{
[Test]
public static void Test()
{
var data = new decimal[1000];
for(int i = 0; i < data.Length; i++)
{
data[i] = RandomNumberGenerator.GetInt32(-10, 10);
}
data[0] = 1000;
var res = Statistics.ClearNSigmaReqursive(data);
Assert.IsTrue(data.Length != res.Length);
Assert.IsTrue(res[0] != 1000);
}
}
}

View File

@ -5,7 +5,8 @@
None = 0,
Stable = 1,
SlowDropping = -1,
Growing = 2,
SlowGrowing = 2,
Growing = 3,
Dropping = -2,
}
}

View File

@ -19,7 +19,6 @@ 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;
@ -37,6 +36,7 @@ namespace KLHZ.Trader.Core.Exchange.Services
private readonly ILogger<Trader> _logger;
private readonly ConcurrentDictionary<string, TradingEvent> LastTradingEvents = new();
private readonly ConcurrentDictionary<string, TradingMode> TradingModes = new();
private readonly ConcurrentDictionary<string, DateTime> LongOpeningStops = new();
@ -95,7 +95,7 @@ namespace KLHZ.Trader.Core.Exchange.Services
public async ValueTask<(DateTime[] timestamps, decimal[] prices, bool isFullIntervalExists)> GetData(INewPrice message, TimeSpan? windowSize = null)
{
var data2 = await _tradeDataProvider.GetData(message.Figi, windowSize??TimeSpan.FromHours(1));
var data2 = await _tradeDataProvider.GetData(message.Figi, windowSize ?? TimeSpan.FromHours(1));
//if (!data2.isFullIntervalExists)
//{
// data2 = await _tradeDataProvider.GetData(message.Figi, TimeSpan.FromHours(0.75));
@ -137,7 +137,7 @@ namespace KLHZ.Trader.Core.Exchange.Services
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.FromMinutes(2), TimeSpan.FromMinutes(30));
fftFull = FFT.Analyze(interpolatedData.timestamps, interpolatedData.values, message.Figi + "_full", TimeSpan.FromMinutes(2), TimeSpan.FromMinutes(30));
//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));
@ -151,7 +151,7 @@ namespace KLHZ.Trader.Core.Exchange.Services
}
//var highFreqData = await GetData(message, TimeSpan.FromMinutes(120));
//if (highFreqData.isFullIntervalExists)
//{
// var interpolatehighFreqData = SignalProcessing.InterpolateData(data.timestamps, data.prices, TimeSpan.FromSeconds(5));
@ -161,7 +161,7 @@ namespace KLHZ.Trader.Core.Exchange.Services
}
position = FFT.Check(fftFull, message.Time);
if (position == Math.Declisions.Dtos.FFT.Enums.ValueAmplitudePosition.UpperThen30Decil)
{
@ -172,7 +172,7 @@ namespace KLHZ.Trader.Core.Exchange.Services
await LogPrice(message, "lower30percent", message.Value);
}
//var hposition = FFT.CheckExtremums(highFreq, message.Time);
//if (hposition == Math.Declisions.Dtos.FFT.Enums.ValueAmplitudePosition.UpperThen30Decil)
@ -220,7 +220,7 @@ namespace KLHZ.Trader.Core.Exchange.Services
|| command.CommandType == Contracts.Messaging.Dtos.Enums.TradeCommandType.OpenShort)
{
var fakeMessage = new NewPriceMessage() { Figi = command.Figi, Ticker = "", Count = command.Count, Direction = 1, IsHistoricalData = false, Time = DateTime.UtcNow, Value = command.RecomendPrice ?? 0m };
var positionType = command.CommandType == TradeCommandType.OpenLong ? PositionType.Long : PositionType.Short;
var positionType = command.CommandType == TradeCommandType.OpenLong ? PositionType.Long : PositionType.Short;
var stops = GetStops(fakeMessage, positionType);
var accounts = _portfolioWrapper.Accounts
.Where(a => !a.Value.Assets.ContainsKey(command.Figi))
@ -259,7 +259,7 @@ namespace KLHZ.Trader.Core.Exchange.Services
{
#region Ускорение обработки исторических данных при отладке
if (message.Direction == 1)
{
{
if (!pricesCache1.TryGetValue(message.Figi, out var list))
{
list = new List<INewPrice>();
@ -320,7 +320,7 @@ namespace KLHZ.Trader.Core.Exchange.Services
#endregion
#region Подсчёт торгового баланса по сберу и IMOEXF
@ -443,7 +443,7 @@ namespace KLHZ.Trader.Core.Exchange.Services
if ((message.Time - dt).TotalSeconds > 10)
{
timesCache[message.Figi] = message.Time;
var newMod = await CalcTradingMode(message);
var newMod = await CalcTradingMode2(message);
if (TradingModes.TryGetValue(message.Figi, out var oldMod))
{
if ((oldMod == TradingMode.Growing || oldMod == TradingMode.Stable)
@ -552,7 +552,7 @@ namespace KLHZ.Trader.Core.Exchange.Services
var sellsOld = sells.Where(b => b.Time < time2 && b.Time >= time1).ToArray();
var buysNew = buys.Where(b => b.Time >= time2).ToArray();
var sellNew = sells.Where(b => b.Time >= time2).ToArray();
if (buysNew.Length>0 && buysOld.Length > 0)
if (buysNew.Length > 0 && buysOld.Length > 0)
{
var dpriceNew = buysNew.Sum(b => b.Value);
var dpriceOld = buysOld.Sum(b => b.Value);
@ -565,42 +565,118 @@ namespace KLHZ.Trader.Core.Exchange.Services
private async Task<ImmutableDictionary<TradingEvent, decimal>> GetSpeedResultantMods(INewPrice message)
{
var res = GetInitDict(1);
//var blocks = GetInitDict(1);
var buys5min = await _tradeDataProvider.GetDataFrom15MinuteWindowCache(message.Figi, Constants._15minBuyCacheKey);
var sells5min = await _tradeDataProvider.GetDataFrom15MinuteWindowCache(message.Figi, Constants._15minSellCacheKey);
var buysSpeed5min = buys5min.Sum(p => p.Value) / 1500;
var sellsSpeed5min = sells5min.Sum(p => p.Value) / 1500;
var buysSpeed5min = buys5min.Sum(p => p.Value) / 900;
var sellsSpeed5min = sells5min.Sum(p => p.Value) / 900;
var diff5min = buysSpeed5min - sellsSpeed5min;
await _tradeDataProvider.AddDataTo5MinuteWindowCache(message.Figi, "diff15min", new Contracts.Declisions.Dtos.CachedValue()
{
Time = message.Time,
Value = diff5min,
});
await LogPrice(message, "speed_diff_15min", diff5min);
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/2 + orderBook.Asks[2].Count/4);
//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);
await LogPrice(message, "asks_lifetime", asks/ buysSpeed5min);
await LogPrice(message, "bids_lifetime", bids/ sellsSpeed5min);
}
if (diff5min < 0)
var bids = (decimal)(orderBook.Bids[0].Count + orderBook.Bids[1].Count/2 + orderBook.Bids[2].Count/4);
var asks_lifetime = asks / buysSpeed5min;
var bids_lifetime = bids / sellsSpeed5min;
var changeModIndicator = (asks_lifetime - bids_lifetime) / (asks_lifetime + bids_lifetime);
await LogPrice(message, "asks_lifetime", asks_lifetime);
await LogPrice(message, "bids_lifetime", bids_lifetime);
await _tradeDataProvider.AddDataTo20SecondsWindowCache(message.Figi, "changemode", new Contracts.Declisions.Dtos.CachedValue()
{
Time = message.Time,
Value = changeModIndicator,
});
var changemodes = await _tradeDataProvider.GetDataFrom20SecondsWindowCache(message.Figi, "changemode");
if (changemodes.Length > 1)
{
await LogPrice(message, "changemode", changemodes[changemodes.Length - 1].Value - changemodes[changemodes.Length - 2].Value);
}
//if (changemodes[changemodes.Length-1].Time - changemodes[0].Time > TimeSpan.FromMinutes(10))
//{
// var diffs = SignalProcessing.CalcDiffs(changemodes.Select(c => c.Value).ToArray());
// var cleareddiffs = Statistics.ClearNSigmaReqursive(diffs,0,3);
// var max = cleareddiffs.Max(d => System.Math.Abs(d));
// var o = changemodes[changemodes.Length - 1].Value - changemodes[changemodes.Length - 2].Value;
// if (System.Math.Abs(o) > max)
// {
// o = 2;// System.Math.Sign(o);
// }
// else
// {
// o= 0;
// }
// await LogPrice(message, "result_lifetime_open", o);
// cleareddiffs = Statistics.ClearNSigmaReqursive(diffs, 0, 10);
// max = cleareddiffs.Max(d => System.Math.Abs(d));
// var s = changemodes[changemodes.Length - 1].Value - changemodes[changemodes.Length - 2].Value;
// if (System.Math.Abs(s) > max)
// {
// if (LastTradingEvents.TryGetValue(message.Figi, out var ev))
// {
// if ((ev & TradingEvent.DowntrendStart) == TradingEvent.DowntrendStart)
// {
// ShortOpeningStops[message.Figi] = message.Time.AddMinutes(10);
// }
// if ((ev & TradingEvent.UptrendStart) == TradingEvent.UptrendStart)
// {
// LongOpeningStops[message.Figi] = message.Time.AddMinutes(10);
// }
// }
// s = 2;// System.Math.Sign(s);
// }
// else
// {
// s = 0;
// }
// await LogPrice(message, "result_lifetime_stop", s);
//}
}
var cached = await _tradeDataProvider.GetDataFrom5MinuteWindowCache(message.Figi, "diff15min");
decimal? diff2 = null;
if (cached.Length > 1)
{
if (cached[cached.Length-1].Time - cached[0].Time > TimeSpan.FromMinutes(3.5))
{
diff2 = cached[cached.Length - 1].Value - cached[0].Value;
}
}
if (diff5min < -0.2m || (diff2.HasValue && diff2<-0.3m))
{
res[TradingEvent.UptrendStart] = Constants.BlockingCoefficient;
}
if (diff5min > 0)
if (diff5min > 0.2m || (diff2.HasValue && diff2 > 0.3m))
{
res[TradingEvent.DowntrendStart] = Constants.BlockingCoefficient;
}
if (diff5min > 6)
if (diff5min > 2m)
{
res[TradingEvent.UptrendEnd] = Constants.BlockingCoefficient;
}
if (diff5min < -6)
if (diff5min < -2m)
{
res[TradingEvent.DowntrendEnd] = Constants.BlockingCoefficient;
}
//res = MergeResultsMult(res, blocks.ToImmutableDictionary());
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)
INewPrice message, int windowMaxSize, decimal? uptrendStartingDetectionMeanfullStep = null, decimal? uptrendEndingDetectionMeanfullStep = null)
{
var resultMoveAvFull = MovingAverage.CheckByWindowAverageMean2(data.timestamps, data.prices,
windowMaxSize, smallWindow, bigWindow, uptrendStartingDetectionMeanfullStep, uptrendEndingDetectionMeanfullStep);
@ -671,6 +747,18 @@ INewPrice message, int windowMaxSize, decimal uptrendStartingDetectionMeanfullSt
if (assetType == AssetType.Futures)
{
if (_tradeDataProvider.Orderbooks.TryGetValue(message.Figi, out var orderbook))
{
if (asset.Count < 0 && orderbook.Asks.Length > 0)
{
price = orderbook.Asks[0].Price;
}
else if (orderbook.Bids.Length > 0)
{
price = orderbook.Bids[0].Price;
}
}
profit = TradingCalculator.CaclProfit(asset.BoughtPrice, price,
GetComission(assetType), GetLeverage(message.Figi, asset.Count < 0), asset.Count < 0);
}
@ -693,11 +781,11 @@ INewPrice message, int windowMaxSize, decimal uptrendStartingDetectionMeanfullSt
}
}
var tasks = assetsForClose.Select(asset => _portfolioWrapper.Accounts[asset.AccountId].ClosePosition(message.Figi));
await Task.WhenAll(tasks);
foreach (var mess in messages)
for (int i = 0; i < assetsForClose.Count; i++)
{
await _dataBus.Broadcast(new MessageForAdmin() { Text = mess });
var asset = assetsForClose[i];
await _portfolioWrapper.Accounts[asset.AccountId].ClosePosition(message.Figi);
await _dataBus.Broadcast(new MessageForAdmin() { Text = messages[i] });
}
}
@ -737,9 +825,10 @@ INewPrice message, int windowMaxSize, decimal uptrendStartingDetectionMeanfullSt
return;
}
var steps = await GetSteps(message);
var windows = await GetWindowsSizes(message);
//var resTask1 = GetWindowAverageStartData(data, 30, 180, message, windowMaxSize, -2m, 2m,3);
var resTask1 = GetWindowAverageStartData(data, (int)windows.smallWindow, (int)windows.bigWindow, message, windowMaxSize, -0.5m, 0.5m);
var resTask1 = GetWindowAverageStartData(data, (int)windows.smallWindow, (int)windows.bigWindow, message, windowMaxSize, steps.downtrendEndStep, steps.uptrendEndStep);
////var resTask3 = GetWindowAverageStartData(data, 30, 180, message, windowMaxSize, 0, 0,0.7m);
var getFFTModsTask = GetFFTMods(message);
//var getLocalTrendsModsTask = GetLocalTrendsMods(data, message);
@ -747,7 +836,7 @@ INewPrice message, int windowMaxSize, decimal uptrendStartingDetectionMeanfullSt
var getTradingModeModsTask = GetTradingModeMods(message);
var getSpeedResultantModsTask = GetSpeedResultantMods(message);
await Task.WhenAll(resTask1, getFFTModsTask, getSellsDiffsModsTask, getTradingModeModsTask, getSpeedResultantModsTask);
await Task.WhenAll(resTask1, getFFTModsTask, getSellsDiffsModsTask, getTradingModeModsTask, getSpeedResultantModsTask);
//var assetType = _tradeDataProvider.GetAssetTypeByFigi(message.Figi);
//if (resTask1.Result[TradingEvent.UptrendStart] >= 1)
//{
@ -759,10 +848,10 @@ INewPrice message, int windowMaxSize, decimal uptrendStartingDetectionMeanfullSt
//result = MergeResults(result, resTask2.Result.ToImmutableDictionary());
//result = MergeResults(result, resTask3.Result.ToImmutableDictionary());
result = MergeResultsMax(result, changeModeData);
// result = MergeResultsMax(result, getLocalTrendsModsTask.Result);
// result = MergeResultsMax(result, getLocalTrendsModsTask.Result);
//result = MergeResultsMult(result, getFFTModsTask.Result);
result = MergeResultsMult(result, getSellsDiffsModsTask.Result);
result = MergeResultsMult(result, getTradingModeModsTask.Result);
//result = MergeResultsMult(result, getTradingModeModsTask.Result);
result = MergeResultsMult(result, getSpeedResultantModsTask.Result);
if (result[TradingEvent.UptrendStart] >= Constants.UppingCoefficient
@ -770,6 +859,7 @@ INewPrice message, int windowMaxSize, decimal uptrendStartingDetectionMeanfullSt
&& state == ExchangeState.Open
)
{
LastTradingEvents[message.Figi] = TradingEvent.UptrendStart;
var stops = GetStops(message, PositionType.Long);
if (!message.IsHistoricalData && BotModeSwitcher.CanPurchase())
{
@ -790,6 +880,7 @@ INewPrice message, int windowMaxSize, decimal uptrendStartingDetectionMeanfullSt
&& state == ExchangeState.Open
)
{
LastTradingEvents[message.Figi] = TradingEvent.DowntrendStart;
var stops = GetStops(message, PositionType.Short);
if (!message.IsHistoricalData && BotModeSwitcher.CanPurchase())
{
@ -938,11 +1029,11 @@ INewPrice message, int windowMaxSize, decimal uptrendStartingDetectionMeanfullSt
return res;
}
private async Task<TradingMode> CalcTradingMode(string figi)
private async ValueTask<TradingMode> CalcTradingMode(INewPrice message)
{
var res = TradingMode.None;
var largeData = await _tradeDataProvider.GetData(figi, TimeSpan.FromMinutes(45));
var smallData = await _tradeDataProvider.GetData(figi, TimeSpan.FromMinutes(10));
var largeData = await _tradeDataProvider.GetData(message.Figi, TimeSpan.FromMinutes(45));
var smallData = await _tradeDataProvider.GetData(message.Figi, TimeSpan.FromMinutes(10));
if (largeData.isFullIntervalExists && smallData.isFullIntervalExists)
{
@ -969,7 +1060,7 @@ INewPrice message, int windowMaxSize, decimal uptrendStartingDetectionMeanfullSt
{
res = TradingMode.Growing;
}
if (smallDataRes < - 7)
if (smallDataRes < -7)
{
res = TradingMode.Dropping;
}
@ -978,12 +1069,72 @@ INewPrice message, int windowMaxSize, decimal uptrendStartingDetectionMeanfullSt
return res;
}
private async Task<TradingMode> CalcTradingMode(INewPrice message)
private async ValueTask<TradingMode> CalcTradingMode2(INewPrice message)
{
var res = await CalcTradingMode(message.Figi);
var res = TradingMode.None;
var data = await _tradeDataProvider.GetData(message.Figi, TimeSpan.FromMinutes(20));
if (data.isFullIntervalExists)
{
if (LocalTrends.TryCalcTrendDiff(data.timestamps, data.prices, out var diff))
{
if (diff >= -2 && diff <= 2)
{
res = TradingMode.Stable;
}
else if (diff < -6)
{
res = TradingMode.Dropping;
}
else if (diff > 6)
{
res = TradingMode.Growing;
}
else if (diff < -2)
{
res = TradingMode.SlowDropping;
}
else if (diff > 2)
{
res = TradingMode.SlowGrowing;
}
}
}
return res;
}
private async Task<(decimal? downtrendEndStep, decimal? uptrendEndStep)> GetSteps(INewPrice message)
{
var mode = TradingModes[message.Figi];
switch (mode)
{
case TradingMode.Stable:
{
return (0.5m, -0.5m);
}
case TradingMode.Dropping:
{
return (-1.5m, null); ;
}
case TradingMode.SlowDropping:
{
return (-0.5m, null);
}
case TradingMode.SlowGrowing:
{
return (null, 0.5m);
}
case TradingMode.Growing:
{
return (null, 1.5m);
}
default:
{
return (-0.5m, 0.5m);
}
}
}
private (decimal stopLoss, decimal takeProfit) GetStops(INewPrice message, PositionType type)
{
var mode = TradingModes[message.Figi];
@ -1016,6 +1167,14 @@ INewPrice message, int windowMaxSize, decimal uptrendStartingDetectionMeanfullSt
takeProfitShift = 1.5m;
stopLossShift = 10;
}
if (mode == TradingMode.SlowGrowing && type == PositionType.Short)
{
takeProfitShift = 1.5m;
stopLossShift = 10;
}
if (mode == TradingMode.SlowGrowing && type == PositionType.Long)
{
}
if (mode == TradingMode.Dropping && type == PositionType.Short)
{
takeProfitShift = 15;
@ -1065,7 +1224,7 @@ INewPrice message, int windowMaxSize, decimal uptrendStartingDetectionMeanfullSt
}
return res.ToImmutableDictionary();
}
private Task<ImmutableDictionary<TradingEvent, decimal>> GetLocalTrendsMods((DateTime[] timestamps, decimal[] prices) data, INewPrice message)
{
var res = GetInitDict(0);
@ -1159,7 +1318,7 @@ INewPrice message, int windowMaxSize, decimal uptrendStartingDetectionMeanfullSt
}
if (mode == TradingMode.Growing)
{
res[TradingEvent.UptrendEnd] = Constants.LowingCoefficient;
//res[TradingEvent.UptrendEnd] = Constants.LowingCoefficient;
res[TradingEvent.UptrendStart] = Constants.UppingCoefficient;
res[TradingEvent.DowntrendStart] = Constants.BlockingCoefficient;
res[TradingEvent.DowntrendEnd] = Constants.PowerUppingCoefficient;
@ -1183,7 +1342,7 @@ INewPrice message, int windowMaxSize, decimal uptrendStartingDetectionMeanfullSt
res[TradingEvent.UptrendEnd] = Constants.PowerUppingCoefficient;
res[TradingEvent.UptrendStart] = Constants.BlockingCoefficient;
res[TradingEvent.DowntrendStart] = Constants.UppingCoefficient;
res[TradingEvent.DowntrendEnd] = Constants.LowingCoefficient;
//res[TradingEvent.DowntrendEnd] = Constants.LowingCoefficient;
}
return Task.FromResult(res.ToImmutableDictionary());
}

View File

@ -120,7 +120,7 @@ namespace KLHZ.Trader.Core.TG.Services
{
var acc = _portfolioWrapper.Accounts.Values.FirstOrDefault(a => a.Assets.ContainsKey("FUTIMOEXF000"));
if (acc != null)
await acc.ResetStops("FUTIMOEXF000", 4, 4);
await acc.ResetStops("FUTIMOEXF000", 4, 4);
break;
}
case "ребут":

View File

@ -1,6 +1,4 @@
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;
@ -10,8 +8,6 @@ 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
{
@ -46,13 +42,13 @@ namespace KLHZ.Trader.Service.Controllers
context1.ChangeTracker.QueryTrackingBehavior = QueryTrackingBehavior.NoTracking;
while (time1 < DateTime.UtcNow)
while (time1 < DateTime.UtcNow.Date)
{
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)
.Where(oi => (oi.Figi == figi1 || oi.Figi == figi2) && oi.Time >= time1 && oi.Time < time2)
.OrderBy(c => c.Time)
.ToArrayAsync();
var prices = await context1.PriceChanges
@ -70,12 +66,12 @@ namespace KLHZ.Trader.Service.Controllers
})
.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);
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)
@ -92,7 +88,7 @@ namespace KLHZ.Trader.Service.Controllers
}
foreach (var bid in bids)
{
var bids2 = bids.Where(b=>b.Price==bid.Price).ToList();
var bids2 = bids.Where(b => b.Price == bid.Price).ToList();
var summCount = bids2.Sum(b => b.Count);
var b = bids2.First();
b.Count = summCount;
@ -180,16 +176,16 @@ namespace KLHZ.Trader.Service.Controllers
data.Add(wrapper);
}
data = data.OrderBy(d => d.Time).ToList();
for(int i = 0; i < data.Count; i++)
for (int i = 0; i < data.Count; i++)
{
if (data[i].NewPrice != null && i>0)
if (data[i].NewPrice != null && i > 0)
{
for (int i1=i-1; i1 >=0; i1--)
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()
var d = new TimeSeriesData()
{
Figi = ob.Figi,
Orderbook = ob,

View File

@ -4,7 +4,7 @@ namespace KLHZ.Trader.Service.Models
{
public class TimeSeriesData
{
public required string Figi { get; set;}
public required string Figi { get; set; }
public DateTime Time { get; set; }
public INewPrice? NewPrice { get; set; }
public IOrderbook? Orderbook { get; set; }