фиксация
parent
8bfcb1968d
commit
9b0253b109
|
@ -10,10 +10,10 @@
|
||||||
return (x, y);
|
return (x, y);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static bool IsLinesCrossing(DateTime time1, DateTime time2, decimal val1_1, decimal val1_2, decimal val2_1, decimal val2_2)
|
public static (bool res,DateTime x, decimal y) IsLinesCrossing(DateTime time1, DateTime time2, decimal val1_1, decimal val1_2, decimal val2_1, decimal val2_2)
|
||||||
{
|
{
|
||||||
var dtime = (decimal)(time2 - time1).TotalSeconds;
|
var dtime = (decimal)(time2 - time1).TotalSeconds;
|
||||||
if (dtime == 0) return false;
|
if (dtime == 0) return (false, DateTime.MinValue,0);
|
||||||
var dval1 = val1_2 - val1_1;
|
var dval1 = val1_2 - val1_1;
|
||||||
var k1 = dval1 / dtime;
|
var k1 = dval1 / dtime;
|
||||||
var b1 = val1_1;
|
var b1 = val1_1;
|
||||||
|
@ -28,10 +28,10 @@
|
||||||
if (cross.x >= 0 && cross.x <= dtime)
|
if (cross.x >= 0 && cross.x <= dtime)
|
||||||
{
|
{
|
||||||
var crossingTimestamp = time1.AddSeconds((double)cross.x);
|
var crossingTimestamp = time1.AddSeconds((double)cross.x);
|
||||||
return crossingTimestamp >= time1 && crossingTimestamp <= time2;
|
return (crossingTimestamp >= time1 && crossingTimestamp <= time2, crossingTimestamp, cross.y);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false;
|
return (false, DateTime.MinValue, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,7 +25,6 @@ namespace KLHZ.Trader.Core.Math.Declisions.Utils
|
||||||
var res = TradingEvent.None;
|
var res = TradingEvent.None;
|
||||||
var bigWindowAv = 0m;
|
var bigWindowAv = 0m;
|
||||||
var smallWindowAv = 0m;
|
var smallWindowAv = 0m;
|
||||||
var s = 0;
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var pricesForFinalComparison = new decimal[size];
|
var pricesForFinalComparison = new decimal[size];
|
||||||
|
@ -33,10 +32,12 @@ namespace KLHZ.Trader.Core.Math.Declisions.Utils
|
||||||
var twavss = new decimal[size];
|
var twavss = new decimal[size];
|
||||||
var twavbs = new decimal[size];
|
var twavbs = new decimal[size];
|
||||||
var times = new DateTime[size];
|
var times = new DateTime[size];
|
||||||
|
var areas = new List<double>();
|
||||||
|
var sign = 1d;
|
||||||
|
var areaValue = 0d;
|
||||||
|
var crossingsCounter = 1;
|
||||||
for (int shift = 0; shift < size - 1 && shift < prices.Length - 1; shift++)
|
for (int shift = 0; shift < size - 1 && shift < prices.Length - 1; shift++)
|
||||||
{
|
{
|
||||||
s = shift;
|
|
||||||
var i2 = size - 1 - shift;
|
var i2 = size - 1 - shift;
|
||||||
var i1 = size - 2 - shift;
|
var i1 = size - 2 - shift;
|
||||||
|
|
||||||
|
@ -49,9 +50,14 @@ namespace KLHZ.Trader.Core.Math.Declisions.Utils
|
||||||
bigWindowAv = twavb.value;
|
bigWindowAv = twavb.value;
|
||||||
smallWindowAv = twavs.value;
|
smallWindowAv = twavs.value;
|
||||||
}
|
}
|
||||||
|
|
||||||
twavss[i2] = twavs.value;
|
twavss[i2] = twavs.value;
|
||||||
twavbs[i2] = twavb.value;
|
twavbs[i2] = twavb.value;
|
||||||
times[i2] = twavb.time;
|
times[i2] = twavb.time;
|
||||||
|
|
||||||
|
var debugArrayB = twavbs.Reverse().ToArray();
|
||||||
|
var debugArrayS = twavss.Reverse().ToArray();
|
||||||
|
var debugArrayT = times.Reverse().ToArray();
|
||||||
if (System.Math.Abs(twavb.value - prices[prices.Length - 1]) > 2 * meanfullStep)
|
if (System.Math.Abs(twavb.value - prices[prices.Length - 1]) > 2 * meanfullStep)
|
||||||
{
|
{
|
||||||
res |= TradingEvent.StopBuy;
|
res |= TradingEvent.StopBuy;
|
||||||
|
@ -67,12 +73,40 @@ namespace KLHZ.Trader.Core.Math.Declisions.Utils
|
||||||
twavbs[i1 + 1],
|
twavbs[i1 + 1],
|
||||||
twavbs[i2 + 1]);
|
twavbs[i2 + 1]);
|
||||||
|
|
||||||
if (shift == 1 && !isCrossing) //если нет пересечения скользящих средний с окном 120 и 15 секунд между
|
if (shift == 1 && !isCrossing.res) //если нет пересечения скользящих средний с окном 120 и 15 секунд между
|
||||||
//текущей и предыдущей точкой - можно не продолжать выполнение.
|
//текущей и предыдущей точкой - можно не продолжать выполнение.
|
||||||
{
|
{
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (shift > 1 && isCrossing)
|
|
||||||
|
if (shift == 1 && isCrossing.res)//обработка ситуации когда одна из точек - совпадение
|
||||||
|
{
|
||||||
|
// если фильтрация окном 120 наползает на окно 15 сверху, потенциальное время открытия лонга и закрытия шорта
|
||||||
|
//if (twavbs[size - 1] <= twavss[size - 1] && twavbs[size - 2] > twavss[size - 2])
|
||||||
|
//{
|
||||||
|
// sign = -1d;
|
||||||
|
//}
|
||||||
|
//// если фильтрация окном 15 наползает на окно 120 сверху, потенциальное время закрытия лонга и возможно открытия шорта
|
||||||
|
//if (twavss[size - 1] <= twavbs[size - 1] && twavss[size - 2] > twavbs[size - 2])
|
||||||
|
//{
|
||||||
|
// sign = 1d;
|
||||||
|
//}
|
||||||
|
// если фильтрация окном 120 наползает на окно 15 сверху, потенциальное время открытия лонга и закрытия шорта
|
||||||
|
if ((debugArrayS[0] == debugArrayB[0] && debugArrayB[1] > debugArrayS[1])
|
||||||
|
|| (debugArrayB[0] < debugArrayS[0] && debugArrayB[1] > debugArrayS[1]))
|
||||||
|
{
|
||||||
|
sign = -1d;
|
||||||
|
}
|
||||||
|
|
||||||
|
// если фильтрация окном 15 наползает на окно 120 снизу, потенциальное время закрытия лонга и возможно открытия шорта
|
||||||
|
if ((debugArrayS[0] == debugArrayB[0] && debugArrayS[1] < debugArrayB[1])
|
||||||
|
|| (debugArrayS[0] > debugArrayB[0] && debugArrayS[1] < debugArrayB[1]))
|
||||||
|
{
|
||||||
|
sign = 1d;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (shift > 1 && isCrossing.res)
|
||||||
{
|
{
|
||||||
// если фильтрация окном 120 наползает на окно 15 сверху, потенциальное время открытия лонга и закрытия шорта
|
// если фильтрация окном 120 наползает на окно 15 сверху, потенциальное время открытия лонга и закрытия шорта
|
||||||
if (twavbs[size - 1] <= twavss[size - 1] && twavbs[size - 2] > twavss[size - 2])
|
if (twavbs[size - 1] <= twavss[size - 1] && twavbs[size - 2] > twavss[size - 2])
|
||||||
|
@ -86,7 +120,8 @@ namespace KLHZ.Trader.Core.Math.Declisions.Utils
|
||||||
}
|
}
|
||||||
|
|
||||||
// если фильтрация окном 15 наползает на окно 120 сверху, потенциальное время закрытия лонга и возможно открытия шорта
|
// если фильтрация окном 15 наползает на окно 120 сверху, потенциальное время закрытия лонга и возможно открытия шорта
|
||||||
if (twavss[size - 1] <= twavbs[size - 1] && twavss[size - 2] > twavbs[size - 2])
|
if ((debugArrayS[0] == debugArrayB[0] && debugArrayS[1] < debugArrayB[1])
|
||||||
|
|| (debugArrayS[0] > debugArrayB[0] && debugArrayS[1] < debugArrayB[1]))
|
||||||
{
|
{
|
||||||
if (pricesForFinalComparison[i2 + 1] - pricesForFinalComparison[size - 1] <= -meanfullStep
|
if (pricesForFinalComparison[i2 + 1] - pricesForFinalComparison[size - 1] <= -meanfullStep
|
||||||
&& timesForFinalComparison[size - 1] - timesForFinalComparison[i2 + 1] >= timeForUptreandStart)
|
&& timesForFinalComparison[size - 1] - timesForFinalComparison[i2 + 1] >= timeForUptreandStart)
|
||||||
|
@ -96,6 +131,26 @@ namespace KLHZ.Trader.Core.Math.Declisions.Utils
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (shift > 1)
|
||||||
|
{
|
||||||
|
if (isCrossing.res)
|
||||||
|
{
|
||||||
|
var ar = ShapeAreaCalculator.CalculateTriangleArea(
|
||||||
|
isCrossing.x, isCrossing.y, times[i1 + 1], twavss[i1 + 1], times[i1 + 1], twavbs[i1 + 1]);
|
||||||
|
areas.Add(ar);
|
||||||
|
areaValue += sign* areas.Sum();
|
||||||
|
sign *= -1;
|
||||||
|
areas.Clear();
|
||||||
|
crossingsCounter++;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var ar = ShapeAreaCalculator.CalculateQuadrilateralArea(
|
||||||
|
times[i1 + 1], twavss[i1 + 1], times[i1 + 1], twavbs[i1 + 1], times[i2 + 1], twavss[i2 + 1], times[i2 + 1], twavbs[i2 + 1]);
|
||||||
|
areas.Add(ar);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,69 @@
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace KLHZ.Trader.Core.Math.Declisions.Utils
|
||||||
|
{
|
||||||
|
public static class ShapeAreaCalculator
|
||||||
|
{
|
||||||
|
// Метод для расчёта площади треугольника
|
||||||
|
public static double CalculateTriangleArea(
|
||||||
|
DateTime pointA_X, decimal pointA_Y,
|
||||||
|
DateTime pointB_X, decimal pointB_Y,
|
||||||
|
DateTime pointC_X, decimal pointC_Y)
|
||||||
|
{
|
||||||
|
// Определяем самую позднюю точку
|
||||||
|
DateTime latestPoint = new[] { pointA_X, pointB_X, pointC_X }.Max();
|
||||||
|
|
||||||
|
// Смещённые координаты
|
||||||
|
double offsetA = GetOffsetInSeconds(latestPoint, pointA_X);
|
||||||
|
double offsetB = GetOffsetInSeconds(latestPoint, pointB_X);
|
||||||
|
double offsetC = GetOffsetInSeconds(latestPoint, pointC_X);
|
||||||
|
|
||||||
|
// Расчёт расстояний
|
||||||
|
double sideAB = DistanceBetweenPoints(offsetA, (double)pointA_Y, offsetB, (double)pointB_Y);
|
||||||
|
double sideBC = DistanceBetweenPoints(offsetB, (double)pointB_Y, offsetC, (double)pointC_Y);
|
||||||
|
double sideCA = DistanceBetweenPoints(offsetC, (double)pointC_Y, offsetA, (double)pointA_Y);
|
||||||
|
|
||||||
|
// Формула Герона
|
||||||
|
double semiPerimeter = (sideAB + sideBC + sideCA) / 2;
|
||||||
|
return System.Math.Sqrt(semiPerimeter * (semiPerimeter - sideAB) *
|
||||||
|
(semiPerimeter - sideBC) * (semiPerimeter - sideCA));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Метод для расчёта площади четырёхугольника
|
||||||
|
public static double CalculateQuadrilateralArea(
|
||||||
|
DateTime pointA_X, decimal pointA_Y,
|
||||||
|
DateTime pointB_X, decimal pointB_Y,
|
||||||
|
DateTime pointC_X, decimal pointC_Y,
|
||||||
|
DateTime pointD_X, decimal pointD_Y)
|
||||||
|
{
|
||||||
|
// Определяем самую позднюю точку
|
||||||
|
DateTime latestPoint = new[] { pointA_X, pointB_X, pointC_X, pointD_X }.Max();
|
||||||
|
|
||||||
|
// Смещённые координаты
|
||||||
|
double offsetA = GetOffsetInSeconds(latestPoint, pointA_X);
|
||||||
|
double offsetB = GetOffsetInSeconds(latestPoint, pointB_X);
|
||||||
|
double offsetC = GetOffsetInSeconds(latestPoint, pointC_X);
|
||||||
|
double offsetD = GetOffsetInSeconds(latestPoint, pointD_X);
|
||||||
|
|
||||||
|
// Суммируем площади двух треугольников
|
||||||
|
double firstTriangleArea = CalculateTriangleArea(pointA_X, pointA_Y, pointB_X, pointB_Y, pointD_X, pointD_Y);
|
||||||
|
double secondTriangleArea = CalculateTriangleArea(pointB_X, pointB_Y, pointC_X, pointC_Y, pointD_X, pointD_Y);
|
||||||
|
|
||||||
|
return firstTriangleArea + secondTriangleArea;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Вспомогательные методы
|
||||||
|
|
||||||
|
// Конвертация разницы времён в секунды
|
||||||
|
private static double GetOffsetInSeconds(DateTime referencePoint, DateTime targetPoint)
|
||||||
|
{
|
||||||
|
return (referencePoint - targetPoint).TotalSeconds;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Евклидово расстояние между двумя точками
|
||||||
|
private static double DistanceBetweenPoints(double x1, double y1, double x2, double y2)
|
||||||
|
{
|
||||||
|
return System.Math.Sqrt(System.Math.Pow(x2 - x1, 2) + System.Math.Pow(y2 - y1, 2));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -16,7 +16,7 @@ namespace KLHZ.Trader.Core.Tests
|
||||||
var val2_1 = -0.5m;
|
var val2_1 = -0.5m;
|
||||||
var val2_2 = 0.5m;
|
var val2_2 = 0.5m;
|
||||||
|
|
||||||
Assert.IsTrue(Lines.IsLinesCrossing(time1, time2, val1_1, val1_2, val2_1, val2_2));
|
Assert.IsTrue(Lines.IsLinesCrossing(time1, time2, val1_1, val1_2, val2_1, val2_2).res);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
|
@ -31,7 +31,7 @@ namespace KLHZ.Trader.Core.Tests
|
||||||
var val2_1 = 0.5m;
|
var val2_1 = 0.5m;
|
||||||
var val2_2 = -0.5m;
|
var val2_2 = -0.5m;
|
||||||
|
|
||||||
Assert.IsFalse(Lines.IsLinesCrossing(time1, time2, val1_1, val1_2, val2_1, val2_2));
|
Assert.IsFalse(Lines.IsLinesCrossing(time1, time2, val1_1, val1_2, val2_1, val2_2).res);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -91,8 +91,8 @@ namespace KLHZ.Trader.Core.Exchange.Services
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
await _tradeDataProvider.AddData(message, TimeSpan.FromHours(7));
|
await _tradeDataProvider.AddData(message, TimeSpan.FromHours(7));
|
||||||
await ProcessDeferredLongOpens(message, currentTime);
|
//await ProcessDeferredLongOpens(message, currentTime);
|
||||||
await ProcessDeferredLongCloses(message, currentTime);
|
//await ProcessDeferredLongCloses(message, currentTime);
|
||||||
if (message.Figi == "FUTIMOEXF000")
|
if (message.Figi == "FUTIMOEXF000")
|
||||||
{
|
{
|
||||||
var windowMaxSize = 1000;
|
var windowMaxSize = 1000;
|
||||||
|
@ -146,7 +146,7 @@ namespace KLHZ.Trader.Core.Exchange.Services
|
||||||
INewPrice message, int windowMaxSize)
|
INewPrice message, int windowMaxSize)
|
||||||
{
|
{
|
||||||
var res = TradingEvent.None;
|
var res = TradingEvent.None;
|
||||||
var resultMoveAvFull = MovingAverage.CheckByWindowAverageMean(data.timestamps, data.prices, windowMaxSize, 45, 180, TimeSpan.FromSeconds(30), 1m);
|
var resultMoveAvFull = MovingAverage.CheckByWindowAverageMean(data.timestamps, data.prices, windowMaxSize, 25, 120, TimeSpan.FromSeconds(20), 1m);
|
||||||
//var resultLongClose = MovingAverage.CheckByWindowAverageMean(data.timestamps, data.prices, windowMaxSize, 15, 120, 1.5m).events;
|
//var resultLongClose = MovingAverage.CheckByWindowAverageMean(data.timestamps, data.prices, windowMaxSize, 15, 120, 1.5m).events;
|
||||||
|
|
||||||
//ar uptrendStarts = LocalTrends.CheckByLocalTrends(data.timestamps, data.prices, TimeSpan.FromSeconds(120), TimeSpan.FromSeconds(20), 1.5m, 15);
|
//ar uptrendStarts = LocalTrends.CheckByLocalTrends(data.timestamps, data.prices, TimeSpan.FromSeconds(120), TimeSpan.FromSeconds(20), 1.5m, 15);
|
||||||
|
|
|
@ -108,7 +108,7 @@ namespace KLHZ.Trader.Core.Exchange.Services
|
||||||
|
|
||||||
public async Task Init()
|
public async Task Init()
|
||||||
{
|
{
|
||||||
await _initSemaphore.WaitAsync(TimeSpan.FromSeconds(15));
|
await _initSemaphore.WaitAsync(TimeSpan.FromSeconds(3));
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var shares = await _investApiClient.Instruments.SharesAsync();
|
var shares = await _investApiClient.Instruments.SharesAsync();
|
||||||
|
|
Loading…
Reference in New Issue