обновление стратегии
test / deploy_trader_prod (push) Successful in 8m39s
Details
test / deploy_trader_prod (push) Successful in 8m39s
Details
parent
23c0dd886b
commit
5547ea50b7
|
@ -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]);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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
|
||||
{
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -5,7 +5,8 @@
|
|||
None = 0,
|
||||
Stable = 1,
|
||||
SlowDropping = -1,
|
||||
Growing = 2,
|
||||
SlowGrowing = 2,
|
||||
Growing = 3,
|
||||
Dropping = -2,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
|
|
|
@ -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 "ребут":
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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; }
|
||||
|
|
Loading…
Reference in New Issue