Compare commits

..

No commits in common. "698af4557636b51d75a4f7f13004a5d8ef39a265" and "fd9e3cdfdb107222f0f6e364371180bb739c498c" have entirely different histories.

11 changed files with 104 additions and 271 deletions

View File

@ -1,6 +1,7 @@
using KLHZ.Trader.Core.DataLayer.Entities.Prices; using KLHZ.Trader.Core.DataLayer.Entities.Prices;
using KLHZ.Trader.Core.Declisions.Models; using KLHZ.Trader.Core.Declisions.Models;
using KLHZ.Trader.Core.Declisions.Utils; using KLHZ.Trader.Core.Declisions.Utils;
using Tinkoff.InvestApi.V1;
namespace KLHZ.Trader.Core.Tests namespace KLHZ.Trader.Core.Tests
{ {

View File

@ -1,5 +1,10 @@
using KLHZ.Trader.Core.Common.Messaging.Contracts.Messages; using KLHZ.Trader.Core.Common.Messaging.Contracts.Messages;
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations.Schema; using System.ComponentModel.DataAnnotations.Schema;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace KLHZ.Trader.Core.DataLayer.Entities.Prices namespace KLHZ.Trader.Core.DataLayer.Entities.Prices
{ {

View File

@ -2,8 +2,7 @@
{ {
public readonly struct PeriodPricesInfo public readonly struct PeriodPricesInfo
{ {
public readonly int Start; public readonly int Count;
public readonly int End;
public readonly float LastPrice; public readonly float LastPrice;
public readonly float FirstPrice; public readonly float FirstPrice;
public readonly float PeriodDiff; public readonly float PeriodDiff;
@ -12,7 +11,7 @@
public readonly bool Success; public readonly bool Success;
public readonly TimeSpan Period; public readonly TimeSpan Period;
public PeriodPricesInfo(bool success, float firstPrice, float lastPrice, float periodDiff, float periodMin, float periodMax, TimeSpan period, int start, int end) public PeriodPricesInfo(bool success, float firstPrice, float lastPrice, float periodDiff, float periodMin, float periodMax, TimeSpan period, int count)
{ {
Success = success; Success = success;
LastPrice = lastPrice; LastPrice = lastPrice;
@ -21,8 +20,7 @@
PeriodMax = periodMax; PeriodMax = periodMax;
PeriodMin = periodMin; PeriodMin = periodMin;
Period = period; Period = period;
Start = start; Count = count;
End = end;
} }
} }
} }

View File

@ -1,27 +0,0 @@
namespace KLHZ.Trader.Core.Declisions.Models
{
public readonly struct TwoPeriodsProcessingData
{
public readonly int Start;
public readonly int Bound;
public readonly int End;
public readonly float DiffStart;
public readonly float DiffEnd;
public readonly bool Success;
public readonly TimeSpan PeriodStart;
public readonly TimeSpan PeriodEnd;
public TwoPeriodsProcessingData(bool success, float diffStart, float diffEnd, int start, int bound, int end,
TimeSpan periodStart, TimeSpan periodEnd)
{
Success = success;
DiffStart = diffStart;
DiffEnd = diffEnd;
Start = start;
Bound = bound;
End = end;
PeriodStart = periodStart;
PeriodEnd = periodEnd;
}
}
}

View File

@ -106,11 +106,11 @@ namespace KLHZ.Trader.Core.Declisions.Services
float meanfullDiff; float meanfullDiff;
if (message.Figi == "BBG004730N88") if (message.Figi == "BBG004730N88")
{ {
meanfullDiff = 0.05f; meanfullDiff = 0.16f;
} }
else if (message.Figi == "FUTIMOEXF000") else if (message.Figi == "FUTIMOEXF000")
{ {
meanfullDiff = 1f; meanfullDiff = 1.5f;
} }
else else
{ {
@ -119,37 +119,30 @@ namespace KLHZ.Trader.Core.Declisions.Services
try try
{ {
//var downtrendStarts = data.CheckDowntrendStarting(TimeSpan.FromSeconds(30), TimeSpan.FromSeconds(7), meanfullDiff); var downtrendStarts = data.CheckDowntrendStarting(TimeSpan.FromSeconds(30), TimeSpan.FromSeconds(7), meanfullDiff);
var uptrendStarts = data.CheckLongOpen(TimeSpan.FromSeconds(60), TimeSpan.FromSeconds(7), meanfullDiff, 8, 3); var uptrendStarts = data.CheckUptrendStarting(TimeSpan.FromSeconds(45), TimeSpan.FromSeconds(10), meanfullDiff);
var uptrendStarts2 = data.CheckLongOpen(TimeSpan.FromSeconds(60), TimeSpan.FromSeconds(3), meanfullDiff, 15, 2);
var downtrendEnds = data.CheckLongOpen(TimeSpan.FromSeconds(120), TimeSpan.FromSeconds(10), meanfullDiff, 15, 5);
uptrendStarts |= downtrendEnds;
uptrendStarts |= uptrendStarts2;
//var downtrendEnds = data.CheckDowntrendEnding(TimeSpan.FromSeconds(60), TimeSpan.FromSeconds(15), meanfullDiff);
var uptrendEnds = data.CheckLongClose(TimeSpan.FromSeconds(15), TimeSpan.FromSeconds(20), meanfullDiff * 1.5f, 8, 8);
var uptrendEnds2 = data.CheckLongClose(TimeSpan.FromSeconds(120), TimeSpan.FromSeconds(30), meanfullDiff, 15, 8);
uptrendEnds |= uptrendEnds2;
var downtrendEnds = data.CheckDowntrendEnding(TimeSpan.FromSeconds(60), TimeSpan.FromSeconds(15), meanfullDiff);
var uptrendEnds = data.CheckUptrendEnding(TimeSpan.FromSeconds(25), TimeSpan.FromSeconds(11), meanfullDiff);
//var uptrendEnds2 = data.CheckUptrendEnding(TimeSpan.FromSeconds(20), TimeSpan.FromSeconds(20), meanfullDiff); //var uptrendEnds2 = data.CheckUptrendEnding(TimeSpan.FromSeconds(20), TimeSpan.FromSeconds(20), meanfullDiff);
//var uptrendEnds = uptrendEnds1 || uptrendEnds2; //var uptrendEnds = uptrendEnds1 || uptrendEnds2;
var declisionAction = DeclisionTradeAction.Unknown; var declisionAction = DeclisionTradeAction.Unknown;
//if (downtrendStarts) if (downtrendStarts)
//{
// //declisionAction = DeclisionTradeAction.OpenShort;
//}
if (uptrendStarts)
{ {
declisionAction = DeclisionTradeAction.OpenLong; //declisionAction = DeclisionTradeAction.OpenShort;
} }
//else if (downtrendEnds) else if (uptrendStarts)
//{ {
// //declisionAction = DeclisionTradeAction.CloseShort; //declisionAction = DeclisionTradeAction.OpenLong;
//} }
else if (uptrendEnds) else if (downtrendEnds)
{
//declisionAction = DeclisionTradeAction.CloseShort;
}
else if(uptrendEnds)
{ {
declisionAction = DeclisionTradeAction.CloseLong; declisionAction = DeclisionTradeAction.CloseLong;
} }
@ -164,7 +157,7 @@ namespace KLHZ.Trader.Core.Declisions.Services
Figi = message.Figi, Figi = message.Figi,
Ticker = message.Ticker, Ticker = message.Ticker,
Price = message.Value, Price = message.Value,
Time = message.IsHistoricalData ? message.Time : DateTime.UtcNow, Time = message.IsHistoricalData? message.Time: DateTime.UtcNow,
Action = declisionAction, Action = declisionAction,
}); });
await context.SaveChangesAsync(); await context.SaveChangesAsync();

View File

@ -6,7 +6,7 @@ namespace KLHZ.Trader.Core.Declisions.Utils
{ {
internal static PeriodPricesInfo GetPriceDiffForTimeSpan(this PriceHistoryCacheUnit unit, TimeSpan timeShift, TimeSpan timeSpan, int? pointsShift = null) internal static PeriodPricesInfo GetPriceDiffForTimeSpan(this PriceHistoryCacheUnit unit, TimeSpan timeShift, TimeSpan timeSpan, int? pointsShift = null)
{ {
var res = new PeriodPricesInfo(false, 0, 0, 0, 0, 0, timeSpan, 0, 0); var res = new PeriodPricesInfo(false, 0, 0, 0, 0, 0, timeSpan, 0);
var data = unit.GetData(); var data = unit.GetData();
var times = data.timestamps; var times = data.timestamps;
var prices = data.prices; var prices = data.prices;
@ -42,7 +42,7 @@ namespace KLHZ.Trader.Core.Declisions.Utils
if (intervaStartIndex != intervaEndIndex && intervaEndIndex >= 0) if (intervaStartIndex != intervaEndIndex && intervaEndIndex >= 0)
break; break;
} }
count++; count++;
} }
if (intervaStartIndex >= 0 && intervaEndIndex >= 0) if (intervaStartIndex >= 0 && intervaEndIndex >= 0)
@ -54,9 +54,7 @@ namespace KLHZ.Trader.Core.Declisions.Utils
prices[intervaEndIndex] - prices[intervaStartIndex], prices[intervaEndIndex] - prices[intervaStartIndex],
min, min,
max, max,
timeSpan, timeSpan, intervaEndIndex - intervaStartIndex);
intervaStartIndex,
intervaEndIndex);
} }
return res; return res;
@ -86,13 +84,6 @@ namespace KLHZ.Trader.Core.Declisions.Utils
if (k2 == 0 && k1 != 0) return 1000; if (k2 == 0 && k1 != 0) return 1000;
return (float)(k1 / k2); return (float)(k1 / k2);
} }
internal static float CalcTrendRelationAbs(TwoPeriodsProcessingData data)
{
var k1 = Math.Abs(data.DiffStart) / Math.Abs(data.PeriodStart.TotalSeconds);
var k2 = Math.Abs(data.DiffEnd) / Math.Abs(data.PeriodEnd.TotalSeconds);
if (k2 == 0 && k1 != 0) return 1000;
return (float)(k1 / k2);
}
internal static bool CheckDowntrendEnding(this PriceHistoryCacheUnit unit, TimeSpan firstPeriod, TimeSpan secondPeriod, float meanfullDiff) internal static bool CheckDowntrendEnding(this PriceHistoryCacheUnit unit, TimeSpan firstPeriod, TimeSpan secondPeriod, float meanfullDiff)
{ {
@ -105,8 +96,8 @@ namespace KLHZ.Trader.Core.Declisions.Utils
var isTotalFalls = totalDiff.CheckFalling(meanfullDiff); var isTotalFalls = totalDiff.CheckFalling(meanfullDiff);
var trendRelation = CalcTrendRelationAbs(startDiff, endDiff); var trendRelation = CalcTrendRelationAbs(startDiff, endDiff);
var res = totalDiff.Success && isStartFalls && (isEndStable || isEndGrown) && trendRelation >= 2; var res = totalDiff.Success && isStartFalls && (isEndStable || isEndGrown) && trendRelation >= 2;
if (startDiff.Success) if (startDiff.Success)
{ {
@ -124,7 +115,7 @@ namespace KLHZ.Trader.Core.Declisions.Utils
var isStartGrows = startDiff.CheckGrowing(meanfullDiff); var isStartGrows = startDiff.CheckGrowing(meanfullDiff);
var trendRelation = CalcTrendRelationAbs(startDiff, endDiff); var trendRelation = CalcTrendRelationAbs(startDiff, endDiff);
var isEndLocal = endDiff.PeriodDiff == 0; var isEndLocal = endDiff.PeriodDiff == 0 && endDiff.Count == 2;
var res = totalDiff.Success && isStartGrows && (isEndStable || isEndFalls) && (trendRelation >= 2 && !isEndLocal); var res = totalDiff.Success && isStartGrows && (isEndStable || isEndFalls) && (trendRelation >= 2 && !isEndLocal);
if (res) if (res)
@ -162,14 +153,14 @@ namespace KLHZ.Trader.Core.Declisions.Utils
var trendRelation = CalcTrendRelationAbs(endDiff, startDiff); var trendRelation = CalcTrendRelationAbs(endDiff, startDiff);
var res = totalDiff.Success && (isStartStable || isStartFalls) && isEndGrows && endDiff.PeriodDiff > meanfullDiff; var res = totalDiff.Success && (isStartStable || isStartFalls) && isEndGrows && endDiff.PeriodDiff > meanfullDiff;
if (isStartStable) if (isStartStable)
{ {
res &= trendRelation >= 2; res &= trendRelation >= 2;
} }
else else
{ {
} }
if (res) if (res)
{ {
@ -177,143 +168,5 @@ namespace KLHZ.Trader.Core.Declisions.Utils
} }
return res; return res;
} }
internal static TwoPeriodsProcessingData GetTwoPeriodsProcessingData(this (DateTime[] timestamps, float[] prices) data, TimeSpan shift, int shiftPointsStart, int shiftPointsEnd, TimeSpan firstPeriod, float meanfullDiff)
{
var res = new TwoPeriodsProcessingData(success: false, 0, 0, 0, 0, 0, TimeSpan.Zero, TimeSpan.Zero);
var time = data.timestamps;
var prices = data.prices;
int count = -1;
var lastTime = time[time.Length - 1];
var bound = -1;
var start = -1;
var end = time.Length - 1;
for (int i = time.Length - 1; i > -1; i--)
{
if (count > 0 && bound < 0 && (count == shiftPointsEnd || lastTime - time[i] >= shift))
{
bound = i;
shift = lastTime - time[i];
}
if (((lastTime - time[i]) >= shift + firstPeriod))
{
start = i;
break;
}
count++;
}
if (start < bound && start >= 0 && bound > 0)
{
var diff1 = prices[bound] - prices[start];
var diff2 = prices[end] - prices[bound];
res = new TwoPeriodsProcessingData(true, diff1, diff2, start, bound, end, time[bound] - time[start], time[end] - time[bound]);
}
return res;
}
internal static bool CheckLongClose(this PriceHistoryCacheUnit unit, TimeSpan firstPeriod, TimeSpan secondPeriod, float meanfullDiff, int pointsStart, int pointsEnd)
{
var data = unit.GetData();
var periodStat = data.GetTwoPeriodsProcessingData(secondPeriod, pointsStart, pointsEnd, firstPeriod, meanfullDiff);
var trendRelation = CalcTrendRelationAbs(periodStat);
var isStartOk = periodStat.Success && periodStat.DiffStart > 0 && periodStat.DiffStart > 1.5 * meanfullDiff;
var isEndOk = periodStat.Success && periodStat.DiffEnd < meanfullDiff;
if (isEndOk)
{
}
if (isStartOk)
{
}
if (isEndOk && isStartOk)
{
}
return isStartOk && isEndOk && (data.prices[periodStat.End] - data.prices[periodStat.Start] >= meanfullDiff);
}
internal static bool CheckUptrendStarting2(this PriceHistoryCacheUnit unit, TimeSpan firstPeriod, TimeSpan secondPeriod, float meanfullDiff)
{
var data = unit.GetData();
var periodStat = data.GetTwoPeriodsProcessingData(secondPeriod, 15, 2, firstPeriod, meanfullDiff);
var trendRelation = CalcTrendRelationAbs(periodStat);
var isStartOk = periodStat.Success && periodStat.DiffStart < -meanfullDiff;
var isEndOk = periodStat.Success && periodStat.DiffEnd >= meanfullDiff;
if (isEndOk)
{
}
if (isStartOk)
{
}
if (isEndOk && isStartOk)
{
}
return isStartOk && isEndOk;
}
internal static bool _CheckUptrendStarting2(this PriceHistoryCacheUnit unit, TimeSpan firstPeriod, TimeSpan secondPeriod, float meanfullDiff)
{
var data = unit.GetData();
var periodStat = data.GetTwoPeriodsProcessingData(secondPeriod, 15, 1, firstPeriod, meanfullDiff);
var trendRelation = CalcTrendRelationAbs(periodStat);
var isStartOk = periodStat.Success && periodStat.DiffStart < -meanfullDiff;
var isEndOk = periodStat.Success && periodStat.DiffEnd >= meanfullDiff;
if (isEndOk)
{
}
if (isStartOk)
{
}
if (isEndOk && isStartOk)
{
}
return isStartOk && isEndOk;
}
internal static bool CheckLongOpen(this PriceHistoryCacheUnit unit, TimeSpan firstPeriod, TimeSpan secondPeriod, float meanfullDiff, int pointsStart, int pointsEnd)
{
var data = unit.GetData();
var periodStat = data.GetTwoPeriodsProcessingData(secondPeriod, pointsStart, pointsEnd, firstPeriod, meanfullDiff);
var trendRelation = CalcTrendRelationAbs(periodStat);
var isStartOk = periodStat.Success && periodStat.DiffStart < -meanfullDiff;
var isEndOk = periodStat.Success && periodStat.DiffEnd >= meanfullDiff;
if (isEndOk)
{
}
if (isStartOk)
{
}
if (isEndOk && isStartOk)
{
}
return isStartOk && isEndOk && (data.prices[periodStat.Start] - data.prices[periodStat.End] >= meanfullDiff);
}
} }
} }

View File

@ -72,7 +72,6 @@ namespace KLHZ.Trader.Core.Exchange.Services
try try
{ {
await SubscribePrices(); await SubscribePrices();
await Task.Delay(1000);
//await SubscribeCandles(); //await SubscribeCandles();
} }
catch (Exception ex) catch (Exception ex)

View File

@ -1,7 +1,11 @@
using Google.Protobuf.WellKnownTypes; using Google.Protobuf.WellKnownTypes;
using KLHZ.Trader.Core.Common.Messaging.Contracts;
using KLHZ.Trader.Core.Common.Messaging.Contracts.Messages;
using KLHZ.Trader.Core.DataLayer; using KLHZ.Trader.Core.DataLayer;
using KLHZ.Trader.Core.DataLayer.Entities.Prices;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Internal;
using Tinkoff.InvestApi; using Tinkoff.InvestApi;
using Tinkoff.InvestApi.V1; using Tinkoff.InvestApi.V1;
using Candle = KLHZ.Trader.Core.DataLayer.Entities.Prices.Candle; using Candle = KLHZ.Trader.Core.DataLayer.Entities.Prices.Candle;

View File

@ -4,3 +4,4 @@ scrape_configs:
scrape_interval: 5s scrape_interval: 5s
static_configs: static_configs:
- targets: ['klhz_trader:8080','gateway.docker.internal:9100'] - targets: ['klhz_trader:8080','gateway.docker.internal:9100']

View File

@ -1,8 +1,14 @@
using Google.Protobuf.WellKnownTypes;
using KLHZ.Trader.Core.Common.Messaging.Contracts; using KLHZ.Trader.Core.Common.Messaging.Contracts;
using KLHZ.Trader.Core.Common.Messaging.Contracts.Messages; using KLHZ.Trader.Core.Common.Messaging.Contracts.Messages;
using KLHZ.Trader.Core.DataLayer; using KLHZ.Trader.Core.DataLayer;
using KLHZ.Trader.Core.DataLayer.Entities.Prices;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Internal;
using Tinkoff.InvestApi;
using Tinkoff.InvestApi.V1;
using Candle = KLHZ.Trader.Core.DataLayer.Entities.Prices.Candle;
namespace KLHZ.Trader.Service.Controllers namespace KLHZ.Trader.Service.Controllers
{ {
@ -24,15 +30,15 @@ namespace KLHZ.Trader.Service.Controllers
{ {
using var context1 = await _dbContextFactory.CreateDbContextAsync(); using var context1 = await _dbContextFactory.CreateDbContextAsync();
context1.ChangeTracker.QueryTrackingBehavior = QueryTrackingBehavior.NoTracking; context1.ChangeTracker.QueryTrackingBehavior = QueryTrackingBehavior.NoTracking;
var data = await context1.PriceChanges var data = await context1.Candles
.Where(c => c.Figi == figi) .Where(c => c.Figi == figi)
.OrderBy(c => c.Time) .OrderBy(c=>c.Time)
.Select(c => new NewPriceMessage() .Select(c => new NewPriceMessage()
{ {
Figi = figi, Figi = figi,
Ticker = c.Ticker, Ticker = c.Ticker,
Time = c.Time, Time = c.Time,
Value = c.Value, Value = c.Close,
IsHistoricalData = true IsHistoricalData = true
}) })
.ToArrayAsync(); .ToArrayAsync();

View File

@ -1,7 +1,7 @@
services: services:
klhz.trader.service: klhz.trader.service:
restart: always restart: always
image: klhz_trader_prod image: klhz_trader
container_name: klhz_trader container_name: klhz_trader
hostname: klhz_trader hostname: klhz_trader
ports: ports:
@ -15,63 +15,63 @@ services:
ExchangeConfig__Token: "${EXCHANGE_API_TOKEN}" ExchangeConfig__Token: "${EXCHANGE_API_TOKEN}"
ConnectionStrings__PostgresConnection: "${PG_CONNECTION_STRING}" ConnectionStrings__PostgresConnection: "${PG_CONNECTION_STRING}"
# postgresql: postgresql:
# ports: ports:
# - 15433:5432 - 15433:5432
# container_name: debug_postgresql_16 container_name: debug_postgresql_16
# hostname: debug_postgresql_16 hostname: debug_postgresql_16
# image: postgres:16 image: postgres:16
# restart: always restart: always
# command: command:
# - "postgres" - "postgres"
# - "-c" - "-c"
# - "max_connections=100" - "max_connections=100"
# - "-c" - "-c"
# - "shared_buffers=512MB" - "shared_buffers=512MB"
# - "-c" - "-c"
# - "temp_buffers=64MB" - "temp_buffers=64MB"
# - "-c" - "-c"
# - "log_statement=all" - "log_statement=all"
# environment: environment:
# POSTGRES_PASSWORD: "${PG_PWD}" POSTGRES_PASSWORD: "${PG_PWD}"
# POSTGRES_DB: trading POSTGRES_DB: trading
# volumes: volumes:
# - traderdata:/var/lib/postgresql/data - traderdata:/var/lib/postgresql/data
# prometheus: prometheus:
# hostname: prometheus hostname: prometheus
# image: prom/prometheus image: prom/prometheus
# container_name: prometheus container_name: prometheus
# ports: ports:
# - 9191:9090 - 9191:9090
# restart: always restart: always
# volumes: volumes:
# - ./KLHZ.Trader.Infrastructure/prometheus/:/etc/prometheus/ - ./KLHZ.Trader.Infrastructure/prometheus/:/etc/prometheus/
# - prom_data:/prometheus - prom_data:/prometheus
# grafana: grafana:
# image: grafana/grafana image: grafana/grafana
# container_name: grafana container_name: grafana
# ports: ports:
# - 1300:3000 - 1300:3000
# restart: always restart: always
# environment: environment:
# GF_SECURITY_ADMIN_USER: "${GF_SECURITY_ADMIN_USER}" GF_SECURITY_ADMIN_USER: "${GF_SECURITY_ADMIN_USER}"
# GF_SECURITY_ADMIN_PASSWORD: "${GF_SECURITY_ADMIN_PASSWORD}" GF_SECURITY_ADMIN_PASSWORD: "${GF_SECURITY_ADMIN_PASSWORD}"
# volumes: volumes:
# - graphana:/etc/grafana/provisioning/datasources - graphana:/etc/grafana/provisioning/datasources
# loki: loki:
# hostname: loki hostname: loki
# image: grafana/loki:latest image: grafana/loki:latest
# container_name: loki container_name: loki
# restart: always restart: always
# ports: ports:
# - "2300:3100" - "2300:3100"
# volumes: volumes:
# - ./KLHZ.Trader.Infrastructure/loki/loki-config.yaml:/etc/loki/local-config.yaml - ./KLHZ.Trader.Infrastructure/loki/loki-config.yaml:/etc/loki/local-config.yaml
# - loki_data:/loki - loki_data:/loki
# command: -config.file=/etc/loki/local-config.yaml command: -config.file=/etc/loki/local-config.yaml
klhz.trader.historyloader: klhz.trader.historyloader:
image: klhztraderhistoryloader image: klhztraderhistoryloader