фиксация первой реализации уровней поддержки
parent
e57d67d5db
commit
167c2ba119
|
@ -0,0 +1,16 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace KLHZ.Trader.Core.Math.Declisions.Dtos
|
||||
{
|
||||
public class ConvolutionResult
|
||||
{
|
||||
public decimal Sum { get; set; }
|
||||
public decimal Value { get;set; }
|
||||
public int Shift { get; set; }
|
||||
public decimal Leverage { get; set; }
|
||||
}
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace KLHZ.Trader.Core.Math.Declisions.Dtos
|
||||
{
|
||||
public class HistItem
|
||||
{
|
||||
public decimal Value { get; set; }
|
||||
public decimal Count { get; set; }
|
||||
}
|
||||
}
|
|
@ -1,4 +1,7 @@
|
|||
namespace KLHZ.Trader.Core.Math.Declisions.Utils
|
||||
using KLHZ.Trader.Core.Contracts.Messaging.Dtos;
|
||||
using KLHZ.Trader.Core.Contracts.Messaging.Dtos.Interfaces;
|
||||
|
||||
namespace KLHZ.Trader.Core.Math.Declisions.Utils
|
||||
{
|
||||
public static class SignalProcessing
|
||||
{
|
||||
|
@ -54,6 +57,103 @@
|
|||
return (res2.ToArray(), res.ToArray());
|
||||
}
|
||||
|
||||
public static ITradeDataItem[] InterpolateData(ITradeDataItem[] items, TimeSpan timeStep)
|
||||
{
|
||||
var result = new List<ITradeDataItem>();
|
||||
|
||||
var firstItem = items[0];
|
||||
var startTime = new DateTime(firstItem.Time.Year, firstItem.Time.Month, firstItem.Time.Day, 0, 0, 0, DateTimeKind.Utc);
|
||||
var dt = items[0].Time - startTime;
|
||||
|
||||
var totalSteps = System.Math.Ceiling((items[items.Length - 1].Time - firstItem.Time).TotalSeconds / timeStep.TotalSeconds);
|
||||
var deltaSeconds = System.Math.Floor(dt.TotalSeconds / timeStep.TotalSeconds);
|
||||
startTime = startTime.AddSeconds(deltaSeconds * timeStep.TotalSeconds);
|
||||
|
||||
var firstBound = startTime;
|
||||
var secondBound = startTime + timeStep;
|
||||
var boundD1 = 0;
|
||||
var boundD2 = 0;
|
||||
for (int i = 0; i < totalSteps; i++)
|
||||
{
|
||||
var countD1 = 0;
|
||||
var sumD1 = 0m;
|
||||
var cD1 = 0L;
|
||||
|
||||
var countD2 = 0;
|
||||
var sumD2 = 0m;
|
||||
var cD2 = 0L;
|
||||
|
||||
for (int i1 = boundD1; i1 < items.Length; i1++)
|
||||
{
|
||||
if (items[i1].Direction == 1)
|
||||
{
|
||||
if (items[i1].Time > firstBound && items[i1].Time <= secondBound)
|
||||
{
|
||||
countD1++;
|
||||
sumD1 += items[i1].Price;
|
||||
cD1 += items[i1].Count;
|
||||
}
|
||||
else if (countD1 != 0)
|
||||
{
|
||||
boundD1 = i1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (int i1 = boundD2; i1 < items.Length; i1++)
|
||||
{
|
||||
if (items[i1].Direction == 2)
|
||||
{
|
||||
if (items[i1].Time > firstBound && items[i1].Time <= secondBound)
|
||||
{
|
||||
countD2++;
|
||||
sumD2 += items[i1].Price;
|
||||
cD2 += items[i1].Count;
|
||||
}
|
||||
else if (countD2 != 0)
|
||||
{
|
||||
boundD2 = i1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (countD1 != 0)
|
||||
{
|
||||
result.Add(new TradeDataItem()
|
||||
{
|
||||
Figi = firstItem.Figi,
|
||||
Ticker = firstItem.Ticker,
|
||||
Price = sumD1 / countD1,
|
||||
Time = secondBound,
|
||||
IsHistoricalData = firstItem.IsHistoricalData,
|
||||
Direction = 1,
|
||||
Count = cD1
|
||||
});
|
||||
}
|
||||
|
||||
if (countD2 != 0)
|
||||
{
|
||||
result.Add(new TradeDataItem()
|
||||
{
|
||||
Figi = firstItem.Figi,
|
||||
Ticker = firstItem.Ticker,
|
||||
Price = sumD2 / countD2,
|
||||
Time = secondBound,
|
||||
IsHistoricalData = firstItem.IsHistoricalData,
|
||||
Direction = 2,
|
||||
Count = cD2
|
||||
});
|
||||
}
|
||||
|
||||
firstBound += timeStep;
|
||||
secondBound += timeStep;
|
||||
}
|
||||
|
||||
|
||||
return result.OrderBy(r => r.Time).ToArray();
|
||||
}
|
||||
|
||||
public static decimal[] CalcDiffs(decimal[] values)
|
||||
{
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
using KLHZ.Trader.Core.Contracts.Messaging.Dtos.Interfaces;
|
||||
using KLHZ.Trader.Core.Math.Declisions.Dtos;
|
||||
|
||||
namespace KLHZ.Trader.Core.Math.Declisions.Utils
|
||||
{
|
||||
|
@ -128,5 +129,91 @@ namespace KLHZ.Trader.Core.Math.Declisions.Utils
|
|||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public static HistItem[] CalcHistogram(ITradeDataItem[] values)
|
||||
{
|
||||
var result = new Dictionary<decimal, decimal>();
|
||||
foreach(var item in values)
|
||||
{
|
||||
if (!result.TryGetValue(item.Price,out var val))
|
||||
{
|
||||
result[item.Price] = 0;
|
||||
}
|
||||
result[item.Price] = val + 1;
|
||||
}
|
||||
return result.Select(r => new HistItem() { Value = r.Key, Count = r.Value }).OrderBy(i=>i.Value).ToArray();
|
||||
}
|
||||
|
||||
public static decimal[] GetParabolaCore(int leverageSize, decimal maxValue = 1)
|
||||
{
|
||||
var d = new double[2 * leverageSize + 1];
|
||||
for (int i = 0; i < d.Length; i++)
|
||||
{
|
||||
d[i] = -System.Math.Pow((i - leverageSize), 2);
|
||||
}
|
||||
|
||||
var min = d.Min();
|
||||
var amin = System.Math.Abs(min);
|
||||
for (int i = 0; i < d.Length; i++)
|
||||
{
|
||||
d[i] = (d[i] - min) / amin * (double)maxValue;
|
||||
}
|
||||
return d.Select(i => (decimal)i).ToArray();
|
||||
}
|
||||
|
||||
public static ConvolutionResult[] CalcConvolution(HistItem[] hist, int leverageSize)
|
||||
{
|
||||
if (hist.Length>2* leverageSize+1)
|
||||
{
|
||||
var results = new List<ConvolutionResult>();
|
||||
var coreSize = 2 * leverageSize + 1;
|
||||
for (int shift = 0; shift < hist.Length - coreSize; shift++)
|
||||
{
|
||||
var s = 0m;
|
||||
var k = 0;
|
||||
for (int i = 0; i < 2 * leverageSize + 1; i++)
|
||||
{
|
||||
var core = GetParabolaCore(leverageSize, hist[i + shift].Count);
|
||||
s += (hist[i + shift].Count - core[i])*(hist[i + shift].Count - core[i]);
|
||||
if (i== leverageSize)
|
||||
{
|
||||
k = i + shift;
|
||||
}
|
||||
}
|
||||
s = s / coreSize;
|
||||
s = (decimal)System.Math.Pow((double)s, 0.5d);
|
||||
//s /= coreSum;
|
||||
results.Add(new ConvolutionResult()
|
||||
{
|
||||
Leverage = leverageSize,
|
||||
Sum = s,
|
||||
Value = hist[k].Value,
|
||||
Shift = k,
|
||||
});
|
||||
}
|
||||
return results.OrderByDescending(r=>r.Value).ToArray();
|
||||
}
|
||||
return Array.Empty<ConvolutionResult>();
|
||||
}
|
||||
|
||||
public static void MergeConvolutionResults(List<ConvolutionResult> results, List<ConvolutionResult> mergedResults)
|
||||
{
|
||||
if (results.Count == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
var resultsOrdered = results.OrderBy(r => r.Sum).ToList();
|
||||
var res = resultsOrdered[0];
|
||||
var b1 = res.Shift - res.Leverage;
|
||||
var b2 = res.Shift + res.Leverage;
|
||||
var forMerge = results.Where(r => r.Shift >= b1 && r.Shift <= b2).ToList();
|
||||
res.Sum = forMerge.Sum(r => r.Sum);
|
||||
foreach (var m in forMerge)
|
||||
{
|
||||
results.Remove(m);
|
||||
}
|
||||
mergedResults.Add(res);
|
||||
MergeConvolutionResults(results, mergedResults);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
using KLHZ.Trader.Core.Math.Declisions.Utils;
|
||||
using KLHZ.Trader.Core.Contracts.Messaging.Dtos;
|
||||
using KLHZ.Trader.Core.Contracts.Messaging.Dtos.Interfaces;
|
||||
using KLHZ.Trader.Core.Math.Declisions.Utils;
|
||||
using System.Security.Cryptography;
|
||||
|
||||
namespace KLHZ.Trader.Core.Tests
|
||||
|
@ -38,5 +40,30 @@ namespace KLHZ.Trader.Core.Tests
|
|||
Assert.IsTrue(r == 1);
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public static void Test3()
|
||||
{
|
||||
var results = new List<ITradeDataItem>();
|
||||
var times = new List<DateTime>();
|
||||
var startDt = DateTime.UtcNow;
|
||||
for (int i = 0; i < 100; i++)
|
||||
{
|
||||
startDt = startDt.AddSeconds(((double)(RandomNumberGenerator.GetInt32(1, 100))) / 100);
|
||||
var t = new TradeDataItem()
|
||||
{
|
||||
Figi = "",
|
||||
Ticker = "",
|
||||
Time = startDt,
|
||||
Count = 1,
|
||||
Direction = RandomNumberGenerator.GetInt32(1, 3),
|
||||
IsHistoricalData = true,
|
||||
Price = (decimal)System.Math.Sin(0.01 * i) + (decimal)System.Math.Cos(0.01 * i),
|
||||
};
|
||||
results.Add(t);
|
||||
}
|
||||
|
||||
var res = SignalProcessing.InterpolateData(results.ToArray(), TimeSpan.FromSeconds(5));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
using KLHZ.Trader.Core.Math.Declisions.Utils;
|
||||
using KLHZ.Trader.Core.Contracts.Declisions.Dtos;
|
||||
using KLHZ.Trader.Core.Math.Declisions.Utils;
|
||||
using System.Security.Cryptography;
|
||||
|
||||
namespace KLHZ.Trader.Core.Tests
|
||||
|
@ -6,7 +7,7 @@ namespace KLHZ.Trader.Core.Tests
|
|||
internal class StatisticTests
|
||||
{
|
||||
[Test]
|
||||
public static void Test()
|
||||
public static void Test1()
|
||||
{
|
||||
var data = new decimal[1000];
|
||||
for (int i = 0; i < data.Length; i++)
|
||||
|
@ -21,5 +22,27 @@ namespace KLHZ.Trader.Core.Tests
|
|||
Assert.IsTrue(data.Length != res.Length);
|
||||
Assert.IsTrue(res[0] != 1000);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public static void Test2()
|
||||
{
|
||||
var data = new decimal[1000];
|
||||
for (int i = 0; i < data.Length; i++)
|
||||
{
|
||||
data[i] = RandomNumberGenerator.GetInt32(-10, 10);
|
||||
}
|
||||
|
||||
|
||||
var res = Statistics.CalcHistogram(data.Select(d=>new CachedValue()
|
||||
{
|
||||
Figi ="",
|
||||
Ticker = "",
|
||||
Direction =1,
|
||||
Price = d/2,
|
||||
Time = DateTime.UtcNow,
|
||||
}).ToArray());
|
||||
|
||||
Statistics.CalcConvolution(res, 5);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -131,7 +131,7 @@ namespace KLHZ.Trader.Core.Exchange.Services
|
|||
var changeMods = TraderUtils.GetInitDict(0);
|
||||
try
|
||||
{
|
||||
message = TraderUtils.FilterHighFreqValues(message, message.Direction == 1 ? pricesCache1 : pricesCache2);
|
||||
//message = TraderUtils.FilterHighFreqValues(message, message.Direction == 1 ? pricesCache1 : pricesCache2);
|
||||
|
||||
#region Добавление данных в кеши.
|
||||
if (message.Figi == "BBG004730N88" || message.Figi == "FUTIMOEXF000")
|
||||
|
|
|
@ -2,9 +2,12 @@ using KLHZ.Trader.Core.Contracts.Messaging.Dtos;
|
|||
using KLHZ.Trader.Core.Contracts.Messaging.Interfaces;
|
||||
using KLHZ.Trader.Core.DataLayer;
|
||||
using KLHZ.Trader.Core.DataLayer.Entities.Orders;
|
||||
using KLHZ.Trader.Core.Math.Declisions.Dtos;
|
||||
using KLHZ.Trader.Core.Math.Declisions.Utils;
|
||||
using KLHZ.Trader.Service.Models;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using System.Linq;
|
||||
|
||||
namespace KLHZ.Trader.Service.Controllers
|
||||
{
|
||||
|
@ -234,6 +237,126 @@ namespace KLHZ.Trader.Service.Controllers
|
|||
}
|
||||
}
|
||||
|
||||
[HttpGet]
|
||||
public async Task RunConvolution(double? shift = null)
|
||||
{
|
||||
var timeStep = 30;
|
||||
var time = DateTime.UtcNow.AddDays(-shift ?? -7).Date;
|
||||
while (time < DateTime.UtcNow)
|
||||
{
|
||||
var forSave = new List<Core.DataLayer.Entities.Prices.ProcessedPrice>();
|
||||
time = time.AddMinutes(timeStep);
|
||||
var figi1 = "FUTIMOEXF000";
|
||||
//var figi1 = "BBG004730N88";
|
||||
var figi2 = "FUTIMOEXF000";
|
||||
//var figi2 = "FUTIMOEXF000";
|
||||
var time2 = time;
|
||||
//var time1 = new DateTime(2025, 9, 24, 11, 00, 0, DateTimeKind.Utc);
|
||||
//var time2 = DateTime.UtcNow.AddMinutes(18);
|
||||
using var context1 = await _dbContextFactory.CreateDbContextAsync();
|
||||
context1.ChangeTracker.QueryTrackingBehavior = QueryTrackingBehavior.NoTracking;
|
||||
|
||||
var time1 = time2.AddHours(-3);
|
||||
var prices = await context1.PriceChanges
|
||||
.Where(c => (c.Figi == figi1 || c.Figi == figi2) && c.Time >= time1 && c.Time < time2 && c.Direction == 1)
|
||||
.OrderBy(c => c.Time)
|
||||
.Select(c => new TradeDataItem()
|
||||
{
|
||||
Figi = c.Figi,
|
||||
Ticker = c.Ticker,
|
||||
Time = c.Time,
|
||||
Price = c.Price,
|
||||
IsHistoricalData = true,
|
||||
Direction = c.Direction,
|
||||
Count = c.Count,
|
||||
})
|
||||
.ToArrayAsync();
|
||||
var pricesToSave = prices.Where(p => p.Time < time && p.Time >= time.AddMinutes(-timeStep)).ToArray();
|
||||
if (pricesToSave.Any())
|
||||
{
|
||||
var p1 = pricesToSave.Last();
|
||||
forSave.Add(new Core.DataLayer.Entities.Prices.ProcessedPrice()
|
||||
{
|
||||
Figi = p1.Figi,
|
||||
Processor = "support_level_calc",
|
||||
Ticker = p1.Ticker,
|
||||
Count = p1.Count,
|
||||
Direction = p1.Direction,
|
||||
Time = p1.Time,
|
||||
Price = p1.Price,
|
||||
});
|
||||
var leverage = 3;
|
||||
var hist = Statistics.CalcHistogram(prices);
|
||||
var convs = Statistics.CalcConvolution(hist, leverage).ToList();
|
||||
//var result = new List<ConvolutionResult>();
|
||||
//Statistics.MergeConvolutionResults(convs, result);
|
||||
var orderedConvs = convs.OrderByDescending(c => c.Sum).Take(5).ToList();
|
||||
orderedConvs = orderedConvs.OrderBy(c => c.Value).ToList();
|
||||
var values = new List<decimal>();
|
||||
var shifts = new List<decimal>();
|
||||
|
||||
foreach (var c in orderedConvs)
|
||||
{
|
||||
var left = c.Value - 0.5m * (leverage - 1);
|
||||
var right = c.Value + 0.5m * (leverage + 1);
|
||||
|
||||
if (values.Count > 0)
|
||||
{
|
||||
var last = values.Last();
|
||||
if (last < left)
|
||||
{
|
||||
values.Add(left);
|
||||
values.Add(right);
|
||||
}
|
||||
else if (last >= left && last < right)
|
||||
{
|
||||
values.Remove(last);
|
||||
values.Add(right);
|
||||
}
|
||||
else if (last >= right)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
values.Add(left);
|
||||
values.Add(right);
|
||||
}
|
||||
}
|
||||
|
||||
var pairs = new List<(decimal left, decimal right)>();
|
||||
for (int i = 0; i < values.Count - 1; i += 2)
|
||||
{
|
||||
pairs.Add((values[i], values[i + 1]));
|
||||
}
|
||||
|
||||
foreach (var price in pricesToSave)
|
||||
{
|
||||
foreach (var p in pairs)
|
||||
{
|
||||
if (price.Price >= p.left && price.Price <= p.right)
|
||||
{
|
||||
forSave.Add(new Core.DataLayer.Entities.Prices.ProcessedPrice()
|
||||
{
|
||||
Figi = price.Figi,
|
||||
Processor = "support_level",
|
||||
Ticker = price.Ticker,
|
||||
Count = price.Count,
|
||||
Direction = price.Direction,
|
||||
Time = price.Time,
|
||||
Price = price.Price,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
await context1.ProcessedPrices.AddRangeAsync(forSave);
|
||||
await context1.SaveChangesAsync();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue