фиксация
test / deploy_trader_prod (push) Successful in 3m3s
Details
test / deploy_trader_prod (push) Successful in 3m3s
Details
parent
9bfff7e4d6
commit
067d7d138d
|
@ -0,0 +1,29 @@
|
|||
using MathNet.Numerics;
|
||||
using MathNet.Numerics.IntegralTransforms;
|
||||
|
||||
namespace KLHZ.Trader.Core.Math.Declisions.Utils
|
||||
{
|
||||
public static class FFT
|
||||
{
|
||||
public static void Test()
|
||||
{
|
||||
var da = new List<float>();
|
||||
for (int i = 0; i < 1000; i++)
|
||||
{
|
||||
da.Add((float)System.Math.Sin(0.01 * i));
|
||||
}
|
||||
|
||||
var start = da.ToArray();
|
||||
var arrv = da.Select(d => new Complex32(d, 0)).ToArray();
|
||||
Fourier.Forward(arrv);
|
||||
|
||||
Fourier.Inverse(arrv);
|
||||
var res = arrv.Select(a => a.Real).ToArray();
|
||||
|
||||
for (int i = 0; i < 1000; i++)
|
||||
{
|
||||
var d = res[i] - start[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,6 +1,5 @@
|
|||
using KLHZ.Trader.Core.Contracts.Declisions.Dtos.Enums;
|
||||
using KLHZ.Trader.Core.Contracts.Declisions.Interfaces;
|
||||
using KLHZ.Trader.Core.Math.Declisions.Dtos;
|
||||
using MathNet.Numerics;
|
||||
|
||||
namespace KLHZ.Trader.Core.Math.Declisions.Utils
|
||||
{
|
||||
|
@ -9,108 +8,97 @@ namespace KLHZ.Trader.Core.Math.Declisions.Utils
|
|||
/// </summary>
|
||||
public static class LocalTrends
|
||||
{
|
||||
public static TradingEvent CheckByLocalTrends(DateTime[] times, decimal[] prices, TimeSpan firstPeriod, TimeSpan secondPeriod, decimal meanfullDiff, int boundIndex)
|
||||
internal static bool TryGetLocalTrends(DateTime[] times, decimal[] prices, TimeSpan firstPeriod, TimeSpan lastPeriod,
|
||||
double meanfullDiff, out TradingEvent res)
|
||||
{
|
||||
var res = TradingEvent.None;
|
||||
res |= CheckUptrendStart(times, prices, firstPeriod, secondPeriod, meanfullDiff, boundIndex);
|
||||
res |= CheckUptrendEnd(times, prices, firstPeriod, secondPeriod, meanfullDiff, boundIndex);
|
||||
res = TradingEvent.None;
|
||||
var success = false;
|
||||
|
||||
return res;
|
||||
}
|
||||
if (times.Length == 0)
|
||||
{
|
||||
return success;
|
||||
}
|
||||
var x1 = new List<double>();
|
||||
var y1 = new List<double>();
|
||||
var x2 = new List<double>();
|
||||
var y2 = new List<double>();
|
||||
var y1_approximated = new List<double>();
|
||||
var y2_approximated = new List<double>();
|
||||
|
||||
internal static TradingEvent CheckUptrendStart(DateTime[] times, decimal[] prices, TimeSpan firstPeriod, TimeSpan secondPeriod, decimal meanfullDiff, int boundIndex)
|
||||
{
|
||||
var periodStat = GetTwoPeriodsProcessingData(times, prices, firstPeriod, secondPeriod, boundIndex, meanfullDiff);
|
||||
var isStartOk = periodStat.Success && periodStat.DiffStart < 0.5m * meanfullDiff;
|
||||
var isEndOk = periodStat.Success && periodStat.DiffEnd >= meanfullDiff;
|
||||
return isStartOk && isEndOk && prices[periodStat.Start] - prices[periodStat.End] >= meanfullDiff ? TradingEvent.UptrendStart : TradingEvent.None;
|
||||
}
|
||||
|
||||
internal static TradingEvent CheckUptrendEnd(DateTime[] times, decimal[] prices, TimeSpan firstPeriod, TimeSpan secondPeriod, decimal meanfullDiff, int boundIndex)
|
||||
{
|
||||
var periodStat = GetTwoPeriodsProcessingData(times, prices, firstPeriod, secondPeriod, boundIndex, meanfullDiff);
|
||||
var isStartOk = periodStat.Success && periodStat.DiffStart > 0 && periodStat.DiffStart > 1.5m * meanfullDiff;
|
||||
var isEndOk = periodStat.Success && periodStat.DiffEnd < meanfullDiff;
|
||||
return isStartOk && isEndOk && prices[periodStat.End] - prices[periodStat.Start] >= meanfullDiff ? TradingEvent.UptrendEnd : TradingEvent.None; ;
|
||||
}
|
||||
|
||||
internal static TwoLocalTrendsResultDto GetTwoPeriodsProcessingData(DateTime[] times, decimal[] prices, TimeSpan firstPeriod, TimeSpan lastPeriod, int boundIndex, decimal meanfullDiff)
|
||||
{
|
||||
var res = new TwoLocalTrendsResultDto(success: false, 0, 0, 0, 0, 0, TimeSpan.Zero, TimeSpan.Zero);
|
||||
int count = -1;
|
||||
var lastTime = times[times.Length - 1];
|
||||
var bound = -1;
|
||||
var start = -1;
|
||||
var end = times.Length - 1;
|
||||
var firstTime = times[0];
|
||||
var fullPeriod = firstPeriod + lastPeriod;
|
||||
|
||||
for (int i = times.Length - 1; i > -1; i--)
|
||||
if (lastTime - firstTime > fullPeriod)
|
||||
{
|
||||
if (count > 0 && bound < 0 && (count == boundIndex || lastTime - times[i] >= lastPeriod))
|
||||
for (int i = 1; i < times.Length - 1; i++)
|
||||
{
|
||||
bound = i;
|
||||
lastPeriod = lastTime - times[i];
|
||||
}
|
||||
if (lastTime - times[i] >= lastPeriod + firstPeriod)
|
||||
{
|
||||
start = i;
|
||||
|
||||
break;
|
||||
var dt1 = lastTime - times[times.Length - i];
|
||||
if (dt1 <= lastPeriod)
|
||||
{
|
||||
x2.Add((times[times.Length - i] - firstTime).TotalSeconds);
|
||||
y2.Add((double)prices[times.Length - i]);
|
||||
}
|
||||
else if (dt1 <= fullPeriod)
|
||||
{
|
||||
x1.Add((times[times.Length - i] - firstTime).TotalSeconds);
|
||||
y1.Add((double)prices[times.Length - i]);
|
||||
}
|
||||
else
|
||||
{
|
||||
success = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
count++;
|
||||
var line1 = Fit.Line(x1.ToArray(), y1.ToArray());
|
||||
var line2 = Fit.Line(x2.ToArray(), y2.ToArray());
|
||||
foreach (var x in x1)
|
||||
{
|
||||
y1_approximated.Add(line1.A + x * line1.B);
|
||||
}
|
||||
foreach (var x in x2)
|
||||
{
|
||||
y2_approximated.Add(line2.A + x * line2.B);
|
||||
}
|
||||
var diff1 = y1_approximated[0] - y1_approximated[y1_approximated.Count - 1];
|
||||
var diff2 = y2_approximated[0] - y2_approximated[y2_approximated.Count - 1];
|
||||
if (diff1 <= -meanfullDiff && diff2 >= meanfullDiff)
|
||||
{
|
||||
res |= TradingEvent.UptrendStart;
|
||||
}
|
||||
else if (diff1 >= meanfullDiff && diff2 <= 0)
|
||||
{
|
||||
res |= TradingEvent.UptrendEnd;
|
||||
}
|
||||
success = true;
|
||||
}
|
||||
|
||||
if (start < bound && start >= 0 && bound > 0)
|
||||
{
|
||||
var diff1 = prices[bound] - prices[start];
|
||||
var diff2 = prices[end] - prices[bound];
|
||||
res = new TwoLocalTrendsResultDto(true, diff1, diff2, start, bound, end, times[bound] - times[start], times[end] - times[bound]);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
internal static bool CheckLongOpen(this IPriceHistoryCacheUnit unit, TimeSpan firstPeriod, TimeSpan secondPeriod, decimal meanfullDiff, int boundIndex)
|
||||
{
|
||||
var data = unit.GetData().Result;
|
||||
var periodStat = GetTwoPeriodsProcessingData(data.timestamps, data.prices, firstPeriod, secondPeriod, boundIndex, meanfullDiff);
|
||||
var isStartOk = periodStat.Success && periodStat.DiffStart < -meanfullDiff;
|
||||
var isEndOk = periodStat.Success && periodStat.DiffEnd >= meanfullDiff;
|
||||
return isStartOk && isEndOk && data.prices[periodStat.Start] - data.prices[periodStat.End] >= meanfullDiff;
|
||||
return success;
|
||||
}
|
||||
|
||||
internal static bool CheckLongClose(this IPriceHistoryCacheUnit unit, TimeSpan firstPeriod, TimeSpan secondPeriod, decimal meanfullDiff, int boundIndex)
|
||||
internal static bool TryCalcTrendDiff(DateTime[] times, decimal[] prices, out decimal diff)
|
||||
{
|
||||
var data = unit.GetData().Result;
|
||||
var periodStat = GetTwoPeriodsProcessingData(data.timestamps, data.prices, firstPeriod, secondPeriod, boundIndex, meanfullDiff);
|
||||
var isStartOk = periodStat.Success && periodStat.DiffStart > 0 && periodStat.DiffStart > 1.5m * meanfullDiff;
|
||||
var isEndOk = periodStat.Success && periodStat.DiffEnd < meanfullDiff;
|
||||
return isStartOk && isEndOk && data.prices[periodStat.End] - data.prices[periodStat.Start] >= meanfullDiff;
|
||||
}
|
||||
|
||||
internal static TradingEvent Detect(IPriceHistoryCacheUnit data)
|
||||
{
|
||||
decimal meanfullDiff = 1m;
|
||||
|
||||
var res = TradingEvent.None;
|
||||
//var downtrendStarts = data.CheckDowntrendStarting(TimeSpan.FromSeconds(30), TimeSpan.FromSeconds(7), meanfullDiff);
|
||||
var uptrendStarts = data.CheckLongOpen(TimeSpan.FromSeconds(60), TimeSpan.FromSeconds(7), meanfullDiff, 3);
|
||||
var uptrendStarts2 = data.CheckLongOpen(TimeSpan.FromSeconds(60), TimeSpan.FromSeconds(3), meanfullDiff, 2);
|
||||
var downtrendEnds = data.CheckLongOpen(TimeSpan.FromSeconds(120), TimeSpan.FromSeconds(10), meanfullDiff, 5);
|
||||
uptrendStarts |= downtrendEnds;
|
||||
uptrendStarts |= uptrendStarts2;
|
||||
if (uptrendStarts)
|
||||
diff = 0;
|
||||
if (times.Length <= 1 || times.Length != prices.Length)
|
||||
{
|
||||
res |= TradingEvent.LongClose;
|
||||
return false;
|
||||
}
|
||||
//var downtrendEnds = data.CheckDowntrendEnding(TimeSpan.FromSeconds(60), TimeSpan.FromSeconds(15), meanfullDiff);
|
||||
|
||||
var uptrendEnds = data.CheckLongClose(TimeSpan.FromSeconds(15), TimeSpan.FromSeconds(20), meanfullDiff * 1.5m, 8);
|
||||
var uptrendEnds2 = data.CheckLongClose(TimeSpan.FromSeconds(120), TimeSpan.FromSeconds(30), meanfullDiff, 8);
|
||||
uptrendEnds |= uptrendEnds2;
|
||||
if (uptrendEnds)
|
||||
else
|
||||
{
|
||||
res |= TradingEvent.LongOpen;
|
||||
var startTime = times[0];
|
||||
var x = new double[times.Length];
|
||||
for (int i = 0; i < times.Length - 1; i++)
|
||||
{
|
||||
x[i] = (times[i] - startTime).TotalSeconds;
|
||||
}
|
||||
var line = Fit.Line(x.ToArray(), prices.Select(p => (double)p).ToArray());
|
||||
|
||||
var p1 = line.A + line.B * 0;
|
||||
var p2 = line.A + line.B * (times[times.Length - 1] - times[0]).TotalSeconds;
|
||||
|
||||
diff = (decimal)(p2 - p1);
|
||||
return true;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="MathNet.Numerics" Version="5.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Hosting.Abstractions" Version="9.0.8" />
|
||||
</ItemGroup>
|
||||
|
||||
|
|
|
@ -0,0 +1,31 @@
|
|||
using MathNet.Numerics;
|
||||
using MathNet.Numerics.IntegralTransforms;
|
||||
using System.Security.Cryptography;
|
||||
|
||||
namespace KLHZ.Trader.Core.Tests
|
||||
{
|
||||
public class FFTTests
|
||||
{
|
||||
[Test]
|
||||
public static void Test()
|
||||
{
|
||||
var da = new List<float>();
|
||||
for (int i = 0; i < 100; i++)
|
||||
{
|
||||
da.Add((float)System.Math.Sin(0.5 * i) + (float)(RandomNumberGenerator.GetInt32(0, 100)) / 300);
|
||||
}
|
||||
|
||||
var start = da.ToArray();
|
||||
var arrv = da.Select(d => new Complex32(d, 0)).ToArray();
|
||||
Fourier.Forward(arrv);
|
||||
|
||||
Fourier.Inverse(arrv);
|
||||
var res = arrv.Select(a => a.Real).ToArray();
|
||||
|
||||
for (int i = 0; i < 1000; i++)
|
||||
{
|
||||
var d = res[i] - start[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,132 @@
|
|||
using KLHZ.Trader.Core.Math.Declisions.Utils;
|
||||
|
||||
namespace KLHZ.Trader.Core.Tests
|
||||
{
|
||||
public class LocalTrendsTests
|
||||
{
|
||||
public static (DateTime[] timestamps, decimal[] prices) GetData(int bound, decimal sign = 1m)
|
||||
{
|
||||
var date1 = DateTime.UtcNow.AddSeconds(-2 * bound);
|
||||
var val = 0m;
|
||||
var timestamps = new List<DateTime>();
|
||||
var prices = new List<decimal>();
|
||||
var step = 0.5m;
|
||||
for (int i = 0; i < 2 * bound; i++)
|
||||
{
|
||||
date1 = date1.AddSeconds(1);
|
||||
timestamps.Add(date1);
|
||||
val += step * sign;
|
||||
prices.Add(val);
|
||||
if (i == bound)
|
||||
{
|
||||
sign = sign * -1;
|
||||
}
|
||||
}
|
||||
|
||||
return (timestamps.ToArray(), prices.ToArray());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TryGetLocalTrends1()
|
||||
{
|
||||
var data = GetData(50);
|
||||
|
||||
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.UptrendEnd);
|
||||
}
|
||||
else
|
||||
{
|
||||
Assert.Fail();
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TryGetLocalTrends2()
|
||||
{
|
||||
var data = GetData(50, -1);
|
||||
|
||||
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);
|
||||
}
|
||||
else
|
||||
{
|
||||
Assert.Fail();
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TryGetLocalTrends3()
|
||||
{
|
||||
var data = GetData(100, -1);
|
||||
|
||||
if (LocalTrends.TryGetLocalTrends(data.timestamps, data.prices, TimeSpan.FromSeconds(30), TimeSpan.FromSeconds(30), 10, out var res))
|
||||
{
|
||||
Assert.That(res == Contracts.Declisions.Dtos.Enums.TradingEvent.None);
|
||||
}
|
||||
else
|
||||
{
|
||||
Assert.Fail();
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TryGetLocalTrends4()
|
||||
{
|
||||
if (LocalTrends.TryGetLocalTrends(Array.Empty<DateTime>(), Array.Empty<decimal>(), TimeSpan.FromSeconds(30), TimeSpan.FromSeconds(30), 10, out var res))
|
||||
{
|
||||
Assert.That(res == Contracts.Declisions.Dtos.Enums.TradingEvent.None);
|
||||
}
|
||||
else
|
||||
{
|
||||
Assert.Pass();
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TryGetLocalTrends5()
|
||||
{
|
||||
if (LocalTrends.TryGetLocalTrends(new DateTime[1] { DateTime.UtcNow }, new decimal[] { 1m }, TimeSpan.FromSeconds(30), TimeSpan.FromSeconds(30), 10, out var res))
|
||||
{
|
||||
Assert.That(res == Contracts.Declisions.Dtos.Enums.TradingEvent.None);
|
||||
}
|
||||
else
|
||||
{
|
||||
Assert.Pass();
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TryCalcTrendDiff1()
|
||||
{
|
||||
var data = GetData(500, -1);
|
||||
|
||||
if (LocalTrends.TryCalcTrendDiff(data.timestamps.Take(100).ToArray(), data.prices.Take(100).ToArray(), out var res))
|
||||
{
|
||||
Assert.That(res < 0);
|
||||
Assert.That(System.Math.Abs(res) <= 50 && System.Math.Abs(res) > 40);
|
||||
}
|
||||
else
|
||||
{
|
||||
Assert.Fail();
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TryCalcTrendDiff2()
|
||||
{
|
||||
var data = GetData(500);
|
||||
|
||||
if (LocalTrends.TryCalcTrendDiff(data.timestamps.Take(100).ToArray(), data.prices.Take(100).ToArray(), out var res))
|
||||
{
|
||||
Assert.That(res > 0);
|
||||
Assert.That(System.Math.Abs(res) <= 50 && System.Math.Abs(res) > 40);
|
||||
}
|
||||
else
|
||||
{
|
||||
Assert.Fail();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -3,8 +3,8 @@
|
|||
public static class BotModeSwitcher
|
||||
{
|
||||
private readonly static object _locker = new();
|
||||
private static bool _canSell = true;
|
||||
private static bool _canPurchase = true;
|
||||
private static bool _canSell = false;
|
||||
private static bool _canPurchase = false;
|
||||
|
||||
public static bool CanSell()
|
||||
{
|
||||
|
|
|
@ -89,7 +89,20 @@ namespace KLHZ.Trader.Core.TG.Services
|
|||
CommandType = TradeCommandType.MarketSell,
|
||||
RecomendPrice = null,
|
||||
Figi = asset.Figi,
|
||||
Count = (long)asset.Count,
|
||||
Count = System.Math.Abs((long)asset.Count),
|
||||
EnableMargin = false,
|
||||
};
|
||||
await _eventBus.Broadcast(command);
|
||||
}
|
||||
if (asset.Count < 0)
|
||||
{
|
||||
var command = new TradeCommand()
|
||||
{
|
||||
AccountId = asset.AccountId,
|
||||
CommandType = TradeCommandType.MarketBuy,
|
||||
RecomendPrice = null,
|
||||
Figi = asset.Figi,
|
||||
Count = System.Math.Abs((long)asset.Count),
|
||||
EnableMargin = false,
|
||||
};
|
||||
await _eventBus.Broadcast(command);
|
||||
|
|
Loading…
Reference in New Issue