реализация нового критерия выставления точки на базе дивергенции

dev
vlad zverzhkhovskiy 2025-10-07 11:21:34 +03:00
parent 03b0f5582e
commit 50938f093e
7 changed files with 356 additions and 136 deletions

View File

@ -188,10 +188,10 @@ namespace KLHZ.Trader.Core.Math.Declisions.Utils
// если фильтрация окном 15 наползает на окно 120 сверху, потенциальное время закрытия лонга и возможно открытия шорта
if (twavss[size - 1] <= twavbs[size - 1] && twavss[size - 2] > twavbs[size - 2])
{
if (!uptrendEndingDetectionMeanfullStep.HasValue || ((d1 >= uptrendEndingDetectionMeanfullStep
if (!uptrendEndingDetectionMeanfullStep.HasValue || ((d1 >= uptrendEndingDetectionMeanfullStep
//|| d2 >= uptrendEndingDetectionMeanfullStep
)
&& dt>TimeSpan.FromSeconds(10)))
)
&& dt > TimeSpan.FromSeconds(10)))
{
res |= TradingEvent.UptrendEnd;
}
@ -200,8 +200,8 @@ namespace KLHZ.Trader.Core.Math.Declisions.Utils
// если фильтрация окном 120 наползает на окно 15 сверху, потенциальное время открытия лонга и закрытия шорта
if (twavss[size - 1] >= twavbs[size - 1] && twavss[size - 2] < twavbs[size - 2])
{
if (!uptrendStartingDetectionMeanfullStep.HasValue ||( (d1 <= uptrendStartingDetectionMeanfullStep
// || d2 <= uptrendStartingDetectionMeanfullStep
if (!uptrendStartingDetectionMeanfullStep.HasValue || ((d1 <= uptrendStartingDetectionMeanfullStep
// || d2 <= uptrendStartingDetectionMeanfullStep
) && dt > TimeSpan.FromSeconds(10)))
{
res |= TradingEvent.UptrendStart;

View File

@ -59,10 +59,10 @@
{
if (values.Length < 1) throw new ArgumentException();
var resArray = new decimal[values.Length-1];
for (int i=1; i<values.Length; i++)
var resArray = new decimal[values.Length - 1];
for (int i = 1; i < values.Length; i++)
{
resArray[i - 1] = values[i] - values[i-1];
resArray[i - 1] = values[i] - values[i - 1];
}
return resArray;
}

View File

@ -1,9 +1,4 @@
using KLHZ.Trader.Core.Contracts.Declisions.Dtos;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace KLHZ.Trader.Core.Math.Declisions.Utils
{
@ -12,13 +7,14 @@ namespace KLHZ.Trader.Core.Math.Declisions.Utils
public static decimal Mean(this CachedValue[] values)
{
return values.Sum(x => x.Value)/ values.Length;
return values.Sum(x => x.Value) / values.Length;
}
public static decimal Mean2(this CachedValue[] values)
{
return values.Sum(x => x.Value2) / values.Length;
}
private static (decimal mean, decimal std) CaclSigma(decimal[] values)
{
var mean = values.Sum() / values.Length;
@ -30,12 +26,12 @@ namespace KLHZ.Trader.Core.Math.Declisions.Utils
data[i] = v * v;
}
var std = System.Math.Pow((double)(data.Sum() / (data.Length - 1)), 0.5);
return (mean,(decimal)std);
return (mean, (decimal)std);
}
public static decimal[] ClearNSigmaReqursive(decimal[] values, int depth = 0, int sigmasCount = 3)
{
if (values.Length <= 1 || depth>10) return values;
if (values.Length <= 1 || depth > 10) return values;
var sigmaRes = CaclSigma(values);
var std = sigmaRes.std;
var mean = sigmaRes.mean;
@ -43,19 +39,72 @@ namespace KLHZ.Trader.Core.Math.Declisions.Utils
var _3std = sigmasCount * std;
foreach (var v in values)
{
if (System.Math.Abs(mean - v)< _3std)
if (System.Math.Abs(mean - v) < _3std)
{
forRes.Add(v);
}
}
if (forRes.Count != values.Length)
{
return ClearNSigmaReqursive(forRes.ToArray(), depth+1);
return ClearNSigmaReqursive(forRes.ToArray(), depth + 1);
}
else
{
return forRes.ToArray();
}
}
public static bool TryCalcTimeWindowsDiff(this CachedValue[] values, TimeSpan boundLeft, TimeSpan boundRight,
Func<CachedValue, decimal> fieldSelector, bool calcMean, out decimal result)
{
result = default;
if (values.Length > 1)
{
var shiftTimeR = values.Last().Time - boundRight;
var shiftTimeL = values.Last().Time - boundLeft;
var valuesOld = values.Where(b => b.Time < shiftTimeR && b.Time >= shiftTimeL).ToArray();
var valuesNew = values.Where(b => b.Time >= shiftTimeR).ToArray();
if (valuesOld.Length > 0 && valuesNew.Length > 0)
{
var valNew = valuesNew.Sum(fieldSelector);
var valOld = valuesOld.Sum(fieldSelector);
if (calcMean)
{
valNew = valNew / valuesNew.Length;
valOld = valOld / valuesOld.Length;
}
result = valNew - valOld;
return true;
}
}
return false;
}
public static bool TryCalcPirsonCorrelation(this CachedValue[] values, TimeSpan period, out decimal result)
{
result = default;
if (values.Any())
{
var shiftTimeDiffs1 = values.Last().Time - period;
values = values.Where(b => b.Time >= shiftTimeDiffs1).ToArray();
if (values.Any())
{
var tradevolume_diffMean = values.Mean();
var dprice_diffMean = values.Mean2();
var sum1 = (double)values.Sum(d => (d.Value - tradevolume_diffMean) * (d.Value2 - dprice_diffMean));
var sum2 = values.Sum(d => (d.Value - tradevolume_diffMean) * (d.Value - tradevolume_diffMean));
var sum3 = values.Sum(d => (d.Value2 - dprice_diffMean) * (d.Value2 - dprice_diffMean));
if (sum2 != 0 && sum3 != 0)
{
result = (decimal)(sum1 / System.Math.Sqrt((double)(sum2 * sum3)));
return true;
}
}
}
return false;
}
}
}

View File

@ -33,7 +33,7 @@ namespace KLHZ.Trader.Core.Tests
var res = SignalProcessing.CalcDiffs(da.ToArray());
Assert.IsTrue(res.Length - da.Count == -1);
foreach(var r in res)
foreach (var r in res)
{
Assert.IsTrue(r == 1);
}

View File

@ -1,10 +1,5 @@
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
{
@ -14,7 +9,7 @@ namespace KLHZ.Trader.Core.Tests
public static void Test()
{
var data = new decimal[1000];
for(int i = 0; i < data.Length; i++)
for (int i = 0; i < data.Length; i++)
{
data[i] = RandomNumberGenerator.GetInt32(-10, 10);
}

View File

@ -40,8 +40,16 @@ namespace KLHZ.Trader.Core.Exchange.Services
private readonly ConcurrentDictionary<string, TradingMode> TradingModes = new();
private readonly ConcurrentDictionary<string, IOrderbook> OrderBooks = new();
private readonly ConcurrentDictionary<string, (DateTime, decimal)> volumes = new();
private readonly ConcurrentDictionary<string, (DateTime, decimal)> prices = new();
private readonly ConcurrentDictionary<string, decimal> privces = new();
private readonly ConcurrentDictionary<string, decimal> privcesDiffDiff = new();
private readonly ConcurrentDictionary<string, decimal> privcesDiffDiffPrev = new();
private readonly ConcurrentDictionary<string, decimal> correlations = new();
private readonly ConcurrentDictionary<string, decimal> correlationsPrev = new();
private readonly ConcurrentDictionary<string, DateTime> PirsonZeroCrossings = new();
private readonly ConcurrentDictionary<string, decimal> DPirsonValues = new();
private readonly ConcurrentDictionary<string, DateTime> PricesZeroCrossingsUp = new();
private readonly ConcurrentDictionary<string, DateTime> PricesZeroCrossingsDown = new();
private readonly ConcurrentDictionary<string, DateTime> LongOpeningStops = new();
private readonly ConcurrentDictionary<string, DateTime> ShortOpeningStops = new();
@ -50,7 +58,6 @@ namespace KLHZ.Trader.Core.Exchange.Services
private readonly ConcurrentDictionary<string, InstrumentSettings> Leverages = new();
private readonly decimal _futureComission;
private readonly decimal _shareComission;
private readonly decimal _accountCashPart;
@ -283,7 +290,7 @@ namespace KLHZ.Trader.Core.Exchange.Services
// if (val != 0)
// await LogPrice(message.Figi, message.Ticker, message.Time, val, "asks0");
// }
//}
OrderBooks[message.Figi] = message;
}
@ -297,6 +304,10 @@ namespace KLHZ.Trader.Core.Exchange.Services
while (await _pricesChannel.Reader.WaitToReadAsync())
{
var message = await _pricesChannel.Reader.ReadAsync();
if (!message.IsHistoricalData && DateTime.UtcNow - message.Time > TimeSpan.FromMinutes(1))
{
continue;
}
var changeMods = GetInitDict(0);
try
{
@ -368,7 +379,7 @@ namespace KLHZ.Trader.Core.Exchange.Services
#region Подсчёт торгового баланса по сберу и IMOEXF
if (message.Figi == "BBG004730N88" || message.Figi == "FUTIMOEXF000")
{
{
if (message.Direction == 1)
{
@ -428,103 +439,134 @@ namespace KLHZ.Trader.Core.Exchange.Services
});
}
//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;
// await LogPrice(message, "asks_lifetime", asksLifetime);
// await LogPrice(message, "buys_speed", buysSpeed);
// }
// if (sellsSpeed > 0)
// {
// var bidsLifetime = bids / sellsSpeed;
// if (bidsLifetime > 600) bidsLifetime = 600;
// await LogPrice(message, "bids_lifetime", bidsLifetime);
// 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)
if (_tradingInstrumentsFigis.Contains(message.Figi) && (message.Figi == "FUTIMOEXF000" || message.Figi == "BBG004730N88") && message.Direction == 1)
{
var smallWindow = TimeSpan.FromSeconds(120);
var bigWindow = TimeSpan.FromSeconds(240);
var meanWindow = TimeSpan.FromSeconds(240);
var currentTime = message.IsHistoricalData ? message.Time : DateTime.UtcNow;
try
{
var buys = await _tradeDataProvider.GetDataFrom5MinuteWindowCache(message.Figi, Constants._5minBuyCacheKey);
var sells = await _tradeDataProvider.GetDataFrom5MinuteWindowCache(message.Figi, Constants._5minSellCacheKey);
if (buys.Any() && sells.Any())
var buys = await _tradeDataProvider.GetDataFrom15MinuteWindowCache(message.Figi, Constants._15minBuyCacheKey);
var sells = await _tradeDataProvider.GetDataFrom15MinuteWindowCache(message.Figi, Constants._15minSellCacheKey);
var trades = buys.ToList();
trades.AddRange(sells);
var trades2 = trades.OrderBy(t => t.Time).ToArray();
if (trades2.TryCalcTimeWindowsDiff(bigWindow, smallWindow, v => v.Value, false, out var tradesDiff)
&& buys.TryCalcTimeWindowsDiff(bigWindow, smallWindow, v => v.Value2, true, out var pricesDiff))
{
var shiftTimeB2 = buys.Last().Time - TimeSpan.FromSeconds(150);
var shiftTimeS2 = sells.Last().Time - TimeSpan.FromSeconds(150);
var shiftTimeB1 = buys.Last().Time - TimeSpan.FromSeconds(300);
var shiftTimeS1 = sells.Last().Time - TimeSpan.FromSeconds(300);
var buysOld = buys.Where(b => b.Time < shiftTimeB2 && b.Time >= shiftTimeB1).ToArray();
var sellsOld = sells.Where(b => b.Time < shiftTimeS2 && b.Time >= shiftTimeS1).ToArray();
var buysNew = buys.Where(b => b.Time >= shiftTimeB2).ToArray();
var sellsNew = sells.Where(b => b.Time >= shiftTimeS2).ToArray();
if (buysOld.Any() && sellsOld.Any() && sellsNew.Any() && buysNew.Any())
await LogPrice(message, "privcesDiff", pricesDiff);
await LogPrice(message, "tradevolume_diff", tradesDiff);
await _tradeDataProvider.AddDataTo15MinuteWindowCache(message.Figi, "5min_diff", new Contracts.Declisions.Dtos.CachedValue()
{
var volume = buysNew.Sum(b => b.Value) + sellsNew.Sum(b => b.Value);
var volumeOld = buysOld.Sum(b => b.Value) + sellsOld.Sum(b => b.Value);
var price = buysNew.Mean2();
var priceOld = buysOld.Mean2();
Time = message.Time,
Value = tradesDiff,
Value2 = pricesDiff,
});
await LogPrice(message, "tradevolume", volume);
await LogPrice(message, "privcesDiff", price- priceOld);
await LogPrice(message, "tradevolume_diff", volume - volumeOld);
var diffs = await _tradeDataProvider.GetDataFrom15MinuteWindowCache(message.Figi, "5min_diff");
if (diffs.TryCalcTimeWindowsDiff(bigWindow, smallWindow, (c) => c.Value2, true, out var resdp)
&& diffs.TryCalcTimeWindowsDiff(bigWindow, smallWindow, (c) => c.Value, true, out var resv))
{
await LogPrice(message, "privcesDiffDiff", (decimal)resdp);
await LogPrice(message, "tradevolume_diff_diff", (decimal)resv);
await _tradeDataProvider.AddDataTo15MinuteWindowCache(message.Figi, "5min_diff_diff", new Contracts.Declisions.Dtos.CachedValue()
{
Time = message.Time,
Value = resv,
Value2 = resdp,
});
if (diffs.TryCalcPirsonCorrelation(meanWindow, out var pirson))
{
await LogPrice(message, "diffs_pirson", (decimal)pirson);
await _tradeDataProvider.AddDataTo15MinuteWindowCache(message.Figi, "diffs_pirson", new Contracts.Declisions.Dtos.CachedValue()
{
Time = message.Time,
Value = (decimal)pirson,
});
if (pirson < 0)
{
//PirsonZeroCrossings["FUTIMOEXF000"] = message.Time;
PirsonZeroCrossings[message.Figi] = message.Time;
// await SetEvents(message);
}
var diffs_pirson = await _tradeDataProvider.GetDataFrom15MinuteWindowCache(message.Figi, "diffs_pirson");
if (diffs_pirson.TryCalcTimeWindowsDiff(bigWindow, smallWindow, (c) => c.Value, true, out var res))
{
await LogPrice(message, "diffs_pirson_diff", (decimal)res);
if (DPirsonValues.TryGetValue(message.Figi, out var olddpirs))
{
if (olddpirs < 0 && res > 0)
{
await LogPrice(message, "diffs_pirson_diff_point0", message.Value);
}
if (olddpirs < 0.25m && res > 0.25m)
{
await LogPrice(message, "diffs_pirson_diff_point0.25", message.Value);
}
if (olddpirs < 0.5m && res > 0.5m)
{
await LogPrice(message, "diffs_pirson_diff_point0.5", message.Value);
}
}
DPirsonValues[message.Figi] = res;
}
}
var diffdiff = await _tradeDataProvider.GetDataFrom15MinuteWindowCache(message.Figi, "5min_diff_diff");
//resdp = diffdiff.Where(d => message.Time - d.Time < TimeSpan.FromSeconds(45)).ToArray().Mean2();
if (privcesDiffDiff.TryGetValue(message.Figi, out var priceOld))
{
privcesDiffDiffPrev[message.Figi] = priceOld;
}
privcesDiffDiff[message.Figi] = pricesDiff;
if (privcesDiffDiff.TryGetValue(message.Figi, out var dprice2)
&& privcesDiffDiffPrev.TryGetValue(message.Figi, out var dprice2_prev))
{
if (((dprice2 < 0 && dprice2_prev > 0) || (dprice2 > 0 && dprice2_prev < 0)))
{
if (PirsonZeroCrossings.TryGetValue(message.Figi, out var pir)
&& message.Time - pir < TimeSpan.FromSeconds(60))
{
if (pricesDiff < 0)
{
PricesZeroCrossingsDown["FUTIMOEXF000"] = message.Time;
//await SetEvents(message);
await LogPrice(message, "price_diff2_point_short", message.Value);
}
if (pricesDiff > 0)
{
PricesZeroCrossingsUp["FUTIMOEXF000"] = message.Time;
//await SetEvents(message);
await LogPrice(message, "price_diff2_point_long", message.Value);
}
}
}
}
if (diffdiff.TryCalcPirsonCorrelation(meanWindow, out var pirson2))
{
if (correlations.TryGetValue(message.Figi, out var corr))
{
correlationsPrev[message.Figi] = corr;
}
await LogPrice(message, "diffs2_pirson", (decimal)pirson2);
correlations[message.Figi] = pirson2;
}
}
}
if (timesCache.TryGetValue(message.Figi, out var dt))
{
if ((message.Time - dt).TotalSeconds > 10)
@ -600,11 +642,11 @@ namespace KLHZ.Trader.Core.Exchange.Services
{
if (message.Direction != 1) continue;
await _tradeDataProvider.AddData(message);
ProcessStops(message, currentTime);
//ProcessStops(message, currentTime);
var windowMaxSize = 2000;
var data = await _tradeDataProvider.GetData(message.Figi, windowMaxSize);
var state = ExchangeScheduler.GetCurrentState(message.Time);
await ProcessNewPriceIMOEXF3(data, state, message, windowMaxSize, changeMods.ToImmutableDictionary());
//var data = await _tradeDataProvider.GetData(message.Figi, windowMaxSize);
//var state = ExchangeScheduler.GetCurrentState(message.Time);
// await ProcessNewPriceIMOEXF3(data, state, message, windowMaxSize, changeMods.ToImmutableDictionary());
}
catch (Exception ex)
{
@ -620,6 +662,28 @@ namespace KLHZ.Trader.Core.Exchange.Services
}
}
//
private async Task SetEvents(INewPrice message)
{
DateTime pz = DateTime.MinValue;
if (PirsonZeroCrossings.TryGetValue(message.Figi, out var pir))
{
if (PricesZeroCrossingsDown.TryGetValue(message.Figi, out pz))
{
if (message.Time - pir < TimeSpan.FromSeconds(120) && message.Time - pz < TimeSpan.FromSeconds(120))
{
await LogPrice(message, "price_diff2_point_short", message.Value);
}
}
if (PricesZeroCrossingsUp.TryGetValue(message.Figi, out pz))
{
if (message.Time - pir < TimeSpan.FromSeconds(120) && message.Time - pz < TimeSpan.FromSeconds(120))
{
await LogPrice(message, "price_diff2_point_long", message.Value);
}
}
}
}
private async Task<ImmutableDictionary<TradingEvent, decimal>> CheckDivergency(DateTime[] timestamps, decimal[] values, INewPrice message)
{
var res = GetInitDict(1);
@ -665,19 +729,19 @@ namespace KLHZ.Trader.Core.Exchange.Services
});
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/2 + orderBook.Asks[2].Count/4);
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/2 + orderBook.Bids[2].Count/4);
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()
{
@ -748,13 +812,13 @@ namespace KLHZ.Trader.Core.Exchange.Services
decimal? diff2 = null;
if (cached.Length > 1)
{
if (cached[cached.Length-1].Time - cached[0].Time > TimeSpan.FromMinutes(3.5))
if (cached[cached.Length - 1].Time - cached[0].Time > TimeSpan.FromMinutes(3.5))
{
diff2 = cached[cached.Length - 1].Value - cached[0].Value;
await LogPrice(message, "changemode2", diff2.Value);
}
}
if (diff5min < -0.2m || (diff2.HasValue && diff2<-0.3m))
if (diff5min < -0.2m || (diff2.HasValue && diff2 < -0.3m))
{
res[TradingEvent.UptrendStart] = Constants.BlockingCoefficient;
}
@ -789,17 +853,90 @@ INewPrice message, int windowMaxSize, decimal? uptrendStartingDetectionMeanfullS
res[TradingEvent.UptrendEnd] = Constants.PowerLowingCoefficient;
if ((resultMoveAvFull.events & TradingEvent.UptrendStart) == TradingEvent.UptrendStart)
{
res[TradingEvent.UptrendStart] = Constants.PowerUppingCoefficient;
res[TradingEvent.DowntrendEnd] = Constants.PowerUppingCoefficient;
res[TradingEvent.UptrendStart] = Constants.UppingCoefficient;
//res[TradingEvent.DowntrendEnd] = Constants.UppingCoefficient;
}
if ((resultMoveAvFull.events & TradingEvent.UptrendEnd) == TradingEvent.UptrendEnd)
{
res[TradingEvent.UptrendEnd] = Constants.PowerUppingCoefficient;
res[TradingEvent.DowntrendStart] = Constants.PowerUppingCoefficient;
//res[TradingEvent.UptrendEnd] = Constants.UppingCoefficient;
res[TradingEvent.DowntrendStart] = Constants.UppingCoefficient;
}
return res;
}
private async Task<Dictionary<TradingEvent, decimal>> GetPriceDiff2Mods((DateTime[] timestamps, decimal[] prices) data, int smallWindow, int bigWindow,
INewPrice message, int windowMaxSize, decimal? uptrendStartingDetectionMeanfullStep = null, decimal? uptrendEndingDetectionMeanfullStep = null)
{
var res = GetInitDict(0);
if (privcesDiffDiff.TryGetValue(message.Figi, out var dprice2) && privcesDiffDiffPrev.TryGetValue(message.Figi, out var dprice2_prev))
{
if ((dprice2 < 0 && dprice2_prev > 0) || (dprice2 > 0 && dprice2_prev < 0))
{
res[TradingEvent.DowntrendStart] = Constants.UppingCoefficient;
}
}
return res;
//res[TradingEvent.DowntrendEnd] = Constants.PowerLowingCoefficient;
//res[TradingEvent.UptrendEnd] = Constants.PowerLowingCoefficient;
//if ((resultMoveAvFull.events & TradingEvent.UptrendStart) == TradingEvent.UptrendStart)
//{
// res[TradingEvent.UptrendStart] = Constants.UppingCoefficient;
// //res[TradingEvent.DowntrendEnd] = Constants.UppingCoefficient;
//}
//if ((resultMoveAvFull.events & TradingEvent.UptrendEnd) == TradingEvent.UptrendEnd)
//{
// //res[TradingEvent.UptrendEnd] = Constants.UppingCoefficient;
// res[TradingEvent.DowntrendStart] = Constants.UppingCoefficient;
//}
//return res;
}
private async Task<Dictionary<TradingEvent, decimal>> GetWindowAverageStartData2((DateTime[] timestamps, decimal[] prices) data, int smallWindow, int bigWindow,
INewPrice message, int windowMaxSize, decimal? uptrendStartingDetectionMeanfullStep = null, decimal? uptrendEndingDetectionMeanfullStep = null)
{
var res = GetInitDict(0);
var resultMoveAvFull = MovingAverage.CheckByWindowAverageMean2(data.timestamps, data.prices,
windowMaxSize, smallWindow, bigWindow, uptrendStartingDetectionMeanfullStep, uptrendEndingDetectionMeanfullStep);
if (resultMoveAvFull.bigWindowAv != 0)
{
await LogPrice(message, Constants.BigWindowCrossingAverageProcessor, resultMoveAvFull.bigWindowAv);
await LogPrice(message, Constants.SmallWindowCrossingAverageProcessor, resultMoveAvFull.smallWindowAv);
}
if (correlationsPrev.TryGetValue(message.Figi, out var oldC) && correlations.TryGetValue(message.Figi, out var c))
{
if ((oldC < 0 && c > 0) || (oldC > 0 && c < 0))
{
if (resultMoveAvFull.bigWindowAv - resultMoveAvFull.smallWindowAv > 0.5m)
{
res[TradingEvent.DowntrendStart] = Constants.UppingCoefficient;
}
if (resultMoveAvFull.smallWindowAv - resultMoveAvFull.bigWindowAv > 0.5m)
{
res[TradingEvent.UptrendStart] = Constants.UppingCoefficient;
}
}
}
return res;
//res[TradingEvent.DowntrendEnd] = Constants.PowerLowingCoefficient;
//res[TradingEvent.UptrendEnd] = Constants.PowerLowingCoefficient;
//if ((resultMoveAvFull.events & TradingEvent.UptrendStart) == TradingEvent.UptrendStart)
//{
// res[TradingEvent.UptrendStart] = Constants.UppingCoefficient;
// //res[TradingEvent.DowntrendEnd] = Constants.UppingCoefficient;
//}
//if ((resultMoveAvFull.events & TradingEvent.UptrendEnd) == TradingEvent.UptrendEnd)
//{
// //res[TradingEvent.UptrendEnd] = Constants.UppingCoefficient;
// res[TradingEvent.DowntrendStart] = Constants.UppingCoefficient;
//}
//return res;
}
private async Task<decimal?> GetAreasRelation((DateTime[] timestamps, decimal[] prices) data, INewPrice message)
{
var areasRel = -1m;
@ -927,7 +1064,9 @@ INewPrice message, int windowMaxSize, decimal? uptrendStartingDetectionMeanfullS
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, steps.downtrendEndStep, steps.uptrendEndStep);
var resTask1 = GetWindowAverageStartData2(data, (int)windows.smallWindow, (int)windows.bigWindow, message, windowMaxSize, steps.downtrendEndStep, steps.uptrendEndStep);
var corrModsTask = GetCorrelationsMods(message);
////var resTask3 = GetWindowAverageStartData(data, 30, 180, message, windowMaxSize, 0, 0,0.7m);
//var getFFTModsTask = GetFFTMods(message);
//var getLocalTrendsModsTask = GetLocalTrendsMods(data, message);
@ -946,13 +1085,16 @@ INewPrice message, int windowMaxSize, decimal? uptrendStartingDetectionMeanfullS
//result = MergeResults(result, resTask2.Result.ToImmutableDictionary());
//result = MergeResults(result, resTask3.Result.ToImmutableDictionary());
result = MergeResultsMax(result, changeModeData);
//result = MergeResultsMax(result, changeModeData);
//result = MergeResultsMult(result, corrModsTask.Result);
// result = MergeResultsMax(result, getLocalTrendsModsTask.Result);
//result = MergeResultsMult(result, getFFTModsTask.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)
&& state == ExchangeState.Open
@ -996,7 +1138,7 @@ INewPrice message, int windowMaxSize, decimal? uptrendStartingDetectionMeanfullS
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 * 10)
{
if (!message.IsHistoricalData && BotModeSwitcher.CanSell())
{
@ -1010,7 +1152,7 @@ INewPrice message, int windowMaxSize, decimal? uptrendStartingDetectionMeanfullS
}
if (result[TradingEvent.DowntrendEnd] >= Constants.UppingCoefficient)
if (result[TradingEvent.DowntrendEnd] >= Constants.UppingCoefficient * 10)
{
if (!message.IsHistoricalData && BotModeSwitcher.CanPurchase())
{
@ -1069,7 +1211,7 @@ INewPrice message, int windowMaxSize, decimal? uptrendStartingDetectionMeanfullS
}, false);
}
private async Task LogPrice(string figi, string ticker,DateTime time, decimal value, string processor)
private async Task LogPrice(string figi, string ticker, DateTime time, decimal value, string processor)
{
await _tradeDataProvider.LogPrice(new ProcessedPrice()
{
@ -1355,6 +1497,40 @@ INewPrice message, int windowMaxSize, decimal? uptrendStartingDetectionMeanfullS
return Task.FromResult(res.ToImmutableDictionary());
}
private async Task<ImmutableDictionary<TradingEvent, decimal>> GetCorrelationsMods(INewPrice message)
{
var res = GetInitDict(1);
return res.ToImmutableDictionary();
if (PirsonZeroCrossings.TryGetValue(message.Figi, out var pir))
{
if (PricesZeroCrossingsUp.TryGetValue(message.Figi, out var prU))
{
var dt1 = message.Time - prU;
var dt2 = message.Time - pir;
if (dt1 < TimeSpan.FromMinutes(0.5) && dt2 < TimeSpan.FromMinutes(0.5))
{
//res[TradingEvent.DowntrendStart] = Constants.UppingCoefficient;
res[TradingEvent.UptrendStart] = Constants.UppingCoefficient;
}
}
if (PricesZeroCrossingsDown.TryGetValue(message.Figi, out var prD))
{
var dt1 = message.Time - prD;
var dt2 = message.Time - pir;
if (dt1 < TimeSpan.FromMinutes(0.5) && dt2 < TimeSpan.FromMinutes(0.5))
{
res[TradingEvent.DowntrendStart] = Constants.UppingCoefficient;
//res[TradingEvent.UptrendStart] = Constants.UppingCoefficient;
}
}
}
return res.ToImmutableDictionary();
}
private async Task<ImmutableDictionary<TradingEvent, decimal>> GetSellsDiffsMods(INewPrice message)
{
var res = GetInitDict(1);

View File

@ -13,7 +13,7 @@
"Token": "",
"ManagingAccountNamePatterns": [ "автотрейд" ],
"DataRecievingInstrumentsFigis": [ "BBG004730N88", "FUTIMOEXF000", "FUTGMKN09250", "FUTBR1025000", "FUTNG0925000", "FUTNASD09250" ],
"TradingInstrumentsFigis": [ "FUTIMOEXF000" ],
"TradingInstrumentsFigis": [ "FUTIMOEXF000", "BBG004730N88" ],
"FutureComission": 0.0025,
"ShareComission": 0.0004,
"AccountCashPart": 0.05,