From d9781ee4e266e5cd5f71edaecbf0a715f90f9cd7 Mon Sep 17 00:00:00 2001 From: vlad zverzhkhovskiy Date: Thu, 28 Aug 2025 02:58:27 +0300 Subject: [PATCH] =?UTF-8?q?=D0=BE=D0=B1=D0=BD=D0=BE=D0=B2=D0=BB=D0=B5?= =?UTF-8?q?=D0=BD=D0=B8=D0=B5=20=D0=BC=D0=B0=D1=82=D0=B5=D0=BC=D0=B0=D1=82?= =?UTF-8?q?=D0=B8=D0=BA=D0=B8=20=D0=B4=D0=BB=D1=8F=20=D0=BB=D0=BE=D0=BD?= =?UTF-8?q?=D0=B3=D0=BE=D0=B2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../HistoryProcessingInstrumentsTests.cs | 1 - .../DataLayer/Entities/Prices/Candle.cs | 5 - .../Declisions/Models/PeriodPricesInfo.cs | 8 +- .../Models/TwoPeriodsProcessingData.cs | 27 +++ .../Declisions/Services/Trader.cs | 43 +++-- .../Utils/HistoryProcessingInstruments.cs | 163 +++++++++++++++++- .../Exchange/Services/ExchangeDataReader.cs | 1 + .../Controllers/LoaderController.cs | 4 - .../prometheus/prometheus.yml | 1 - .../Controllers/PlayController.cs | 12 +- docker-compose.yml | 110 ++++++------ 11 files changed, 271 insertions(+), 104 deletions(-) create mode 100644 KLHZ.Trader.Core/Declisions/Models/TwoPeriodsProcessingData.cs diff --git a/KLHZ.Trader.Core.Tests/HistoryProcessingInstrumentsTests.cs b/KLHZ.Trader.Core.Tests/HistoryProcessingInstrumentsTests.cs index 88c7650..9f7d359 100644 --- a/KLHZ.Trader.Core.Tests/HistoryProcessingInstrumentsTests.cs +++ b/KLHZ.Trader.Core.Tests/HistoryProcessingInstrumentsTests.cs @@ -1,7 +1,6 @@ using KLHZ.Trader.Core.DataLayer.Entities.Prices; using KLHZ.Trader.Core.Declisions.Models; using KLHZ.Trader.Core.Declisions.Utils; -using Tinkoff.InvestApi.V1; namespace KLHZ.Trader.Core.Tests { diff --git a/KLHZ.Trader.Core/DataLayer/Entities/Prices/Candle.cs b/KLHZ.Trader.Core/DataLayer/Entities/Prices/Candle.cs index d6a2861..c1e7eee 100644 --- a/KLHZ.Trader.Core/DataLayer/Entities/Prices/Candle.cs +++ b/KLHZ.Trader.Core/DataLayer/Entities/Prices/Candle.cs @@ -1,10 +1,5 @@ using KLHZ.Trader.Core.Common.Messaging.Contracts.Messages; -using System; -using System.Collections.Generic; using System.ComponentModel.DataAnnotations.Schema; -using System.Linq; -using System.Text; -using System.Threading.Tasks; namespace KLHZ.Trader.Core.DataLayer.Entities.Prices { diff --git a/KLHZ.Trader.Core/Declisions/Models/PeriodPricesInfo.cs b/KLHZ.Trader.Core/Declisions/Models/PeriodPricesInfo.cs index 46fcf80..360c46b 100644 --- a/KLHZ.Trader.Core/Declisions/Models/PeriodPricesInfo.cs +++ b/KLHZ.Trader.Core/Declisions/Models/PeriodPricesInfo.cs @@ -2,7 +2,8 @@ { public readonly struct PeriodPricesInfo { - public readonly int Count; + public readonly int Start; + public readonly int End; public readonly float LastPrice; public readonly float FirstPrice; public readonly float PeriodDiff; @@ -11,7 +12,7 @@ public readonly bool Success; public readonly TimeSpan Period; - public PeriodPricesInfo(bool success, float firstPrice, float lastPrice, float periodDiff, float periodMin, float periodMax, TimeSpan period, int count) + public PeriodPricesInfo(bool success, float firstPrice, float lastPrice, float periodDiff, float periodMin, float periodMax, TimeSpan period, int start, int end) { Success = success; LastPrice = lastPrice; @@ -20,7 +21,8 @@ PeriodMax = periodMax; PeriodMin = periodMin; Period = period; - Count = count; + Start = start; + End = end; } } } diff --git a/KLHZ.Trader.Core/Declisions/Models/TwoPeriodsProcessingData.cs b/KLHZ.Trader.Core/Declisions/Models/TwoPeriodsProcessingData.cs new file mode 100644 index 0000000..fb835a3 --- /dev/null +++ b/KLHZ.Trader.Core/Declisions/Models/TwoPeriodsProcessingData.cs @@ -0,0 +1,27 @@ +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; + } + } +} diff --git a/KLHZ.Trader.Core/Declisions/Services/Trader.cs b/KLHZ.Trader.Core/Declisions/Services/Trader.cs index e981f6b..14cff7b 100644 --- a/KLHZ.Trader.Core/Declisions/Services/Trader.cs +++ b/KLHZ.Trader.Core/Declisions/Services/Trader.cs @@ -106,11 +106,11 @@ namespace KLHZ.Trader.Core.Declisions.Services float meanfullDiff; if (message.Figi == "BBG004730N88") { - meanfullDiff = 0.16f; + meanfullDiff = 0.05f; } else if (message.Figi == "FUTIMOEXF000") { - meanfullDiff = 1.5f; + meanfullDiff = 1f; } else { @@ -119,30 +119,37 @@ namespace KLHZ.Trader.Core.Declisions.Services try { - var downtrendStarts = data.CheckDowntrendStarting(TimeSpan.FromSeconds(30), TimeSpan.FromSeconds(7), meanfullDiff); - var uptrendStarts = data.CheckUptrendStarting(TimeSpan.FromSeconds(45), TimeSpan.FromSeconds(10), 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 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 uptrendEnds = uptrendEnds1 || uptrendEnds2; var declisionAction = DeclisionTradeAction.Unknown; - if (downtrendStarts) + //if (downtrendStarts) + //{ + // //declisionAction = DeclisionTradeAction.OpenShort; + //} + if (uptrendStarts) { - //declisionAction = DeclisionTradeAction.OpenShort; + declisionAction = DeclisionTradeAction.OpenLong; } - else if (uptrendStarts) - { - //declisionAction = DeclisionTradeAction.OpenLong; - } - else if (downtrendEnds) - { - //declisionAction = DeclisionTradeAction.CloseShort; - } - else if(uptrendEnds) + //else if (downtrendEnds) + //{ + // //declisionAction = DeclisionTradeAction.CloseShort; + //} + else if (uptrendEnds) { declisionAction = DeclisionTradeAction.CloseLong; } @@ -157,7 +164,7 @@ namespace KLHZ.Trader.Core.Declisions.Services Figi = message.Figi, Ticker = message.Ticker, Price = message.Value, - Time = message.IsHistoricalData? message.Time: DateTime.UtcNow, + Time = message.IsHistoricalData ? message.Time : DateTime.UtcNow, Action = declisionAction, }); await context.SaveChangesAsync(); diff --git a/KLHZ.Trader.Core/Declisions/Utils/HistoryProcessingInstruments.cs b/KLHZ.Trader.Core/Declisions/Utils/HistoryProcessingInstruments.cs index 9563976..5411b4e 100644 --- a/KLHZ.Trader.Core/Declisions/Utils/HistoryProcessingInstruments.cs +++ b/KLHZ.Trader.Core/Declisions/Utils/HistoryProcessingInstruments.cs @@ -6,7 +6,7 @@ namespace KLHZ.Trader.Core.Declisions.Utils { 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); + var res = new PeriodPricesInfo(false, 0, 0, 0, 0, 0, timeSpan, 0, 0); var data = unit.GetData(); var times = data.timestamps; var prices = data.prices; @@ -42,7 +42,7 @@ namespace KLHZ.Trader.Core.Declisions.Utils if (intervaStartIndex != intervaEndIndex && intervaEndIndex >= 0) break; } - count++; + count++; } if (intervaStartIndex >= 0 && intervaEndIndex >= 0) @@ -54,7 +54,9 @@ namespace KLHZ.Trader.Core.Declisions.Utils prices[intervaEndIndex] - prices[intervaStartIndex], min, max, - timeSpan, intervaEndIndex - intervaStartIndex); + timeSpan, + intervaStartIndex, + intervaEndIndex); } return res; @@ -84,6 +86,13 @@ namespace KLHZ.Trader.Core.Declisions.Utils if (k2 == 0 && k1 != 0) return 1000; 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) { @@ -96,8 +105,8 @@ namespace KLHZ.Trader.Core.Declisions.Utils var isTotalFalls = totalDiff.CheckFalling(meanfullDiff); 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) { @@ -115,7 +124,7 @@ namespace KLHZ.Trader.Core.Declisions.Utils var isStartGrows = startDiff.CheckGrowing(meanfullDiff); var trendRelation = CalcTrendRelationAbs(startDiff, endDiff); - var isEndLocal = endDiff.PeriodDiff == 0 && endDiff.Count == 2; + var isEndLocal = endDiff.PeriodDiff == 0; var res = totalDiff.Success && isStartGrows && (isEndStable || isEndFalls) && (trendRelation >= 2 && !isEndLocal); if (res) @@ -153,14 +162,14 @@ namespace KLHZ.Trader.Core.Declisions.Utils var trendRelation = CalcTrendRelationAbs(endDiff, startDiff); var res = totalDiff.Success && (isStartStable || isStartFalls) && isEndGrows && endDiff.PeriodDiff > meanfullDiff; - + if (isStartStable) { res &= trendRelation >= 2; } else { - + } if (res) { @@ -168,5 +177,143 @@ namespace KLHZ.Trader.Core.Declisions.Utils } 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); + } } } diff --git a/KLHZ.Trader.Core/Exchange/Services/ExchangeDataReader.cs b/KLHZ.Trader.Core/Exchange/Services/ExchangeDataReader.cs index 006866a..5a3fa95 100644 --- a/KLHZ.Trader.Core/Exchange/Services/ExchangeDataReader.cs +++ b/KLHZ.Trader.Core/Exchange/Services/ExchangeDataReader.cs @@ -72,6 +72,7 @@ namespace KLHZ.Trader.Core.Exchange.Services try { await SubscribePrices(); + await Task.Delay(1000); //await SubscribeCandles(); } catch (Exception ex) diff --git a/KLHZ.Trader.HistoryLoader/Controllers/LoaderController.cs b/KLHZ.Trader.HistoryLoader/Controllers/LoaderController.cs index a1f3837..3f7d7b0 100644 --- a/KLHZ.Trader.HistoryLoader/Controllers/LoaderController.cs +++ b/KLHZ.Trader.HistoryLoader/Controllers/LoaderController.cs @@ -1,11 +1,7 @@ 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.Entities.Prices; using Microsoft.AspNetCore.Mvc; using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Internal; using Tinkoff.InvestApi; using Tinkoff.InvestApi.V1; using Candle = KLHZ.Trader.Core.DataLayer.Entities.Prices.Candle; diff --git a/KLHZ.Trader.Infrastructure/prometheus/prometheus.yml b/KLHZ.Trader.Infrastructure/prometheus/prometheus.yml index 93068f3..9f571c1 100644 --- a/KLHZ.Trader.Infrastructure/prometheus/prometheus.yml +++ b/KLHZ.Trader.Infrastructure/prometheus/prometheus.yml @@ -4,4 +4,3 @@ scrape_configs: scrape_interval: 5s static_configs: - targets: ['klhz_trader:8080','gateway.docker.internal:9100'] - \ No newline at end of file diff --git a/KLHZ.Trader.Service/Controllers/PlayController.cs b/KLHZ.Trader.Service/Controllers/PlayController.cs index a9bad06..a8f2319 100644 --- a/KLHZ.Trader.Service/Controllers/PlayController.cs +++ b/KLHZ.Trader.Service/Controllers/PlayController.cs @@ -1,14 +1,8 @@ -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.Entities.Prices; using Microsoft.AspNetCore.Mvc; 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 { @@ -30,15 +24,15 @@ namespace KLHZ.Trader.Service.Controllers { using var context1 = await _dbContextFactory.CreateDbContextAsync(); context1.ChangeTracker.QueryTrackingBehavior = QueryTrackingBehavior.NoTracking; - var data = await context1.Candles + var data = await context1.PriceChanges .Where(c => c.Figi == figi) - .OrderBy(c=>c.Time) + .OrderBy(c => c.Time) .Select(c => new NewPriceMessage() { Figi = figi, Ticker = c.Ticker, Time = c.Time, - Value = c.Close, + Value = c.Value, IsHistoricalData = true }) .ToArrayAsync(); diff --git a/docker-compose.yml b/docker-compose.yml index 5e760c6..ac074a2 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,7 +1,7 @@ services: klhz.trader.service: restart: always - image: klhz_trader + image: klhz_trader_prod container_name: klhz_trader hostname: klhz_trader ports: @@ -15,63 +15,63 @@ services: ExchangeConfig__Token: "${EXCHANGE_API_TOKEN}" ConnectionStrings__PostgresConnection: "${PG_CONNECTION_STRING}" - postgresql: - ports: - - 15433:5432 - container_name: debug_postgresql_16 - hostname: debug_postgresql_16 - image: postgres:16 - restart: always - command: - - "postgres" - - "-c" - - "max_connections=100" - - "-c" - - "shared_buffers=512MB" - - "-c" - - "temp_buffers=64MB" - - "-c" - - "log_statement=all" - environment: - POSTGRES_PASSWORD: "${PG_PWD}" - POSTGRES_DB: trading - volumes: - - traderdata:/var/lib/postgresql/data + # postgresql: + # ports: + # - 15433:5432 + # container_name: debug_postgresql_16 + # hostname: debug_postgresql_16 + # image: postgres:16 + # restart: always + # command: + # - "postgres" + # - "-c" + # - "max_connections=100" + # - "-c" + # - "shared_buffers=512MB" + # - "-c" + # - "temp_buffers=64MB" + # - "-c" + # - "log_statement=all" + # environment: + # POSTGRES_PASSWORD: "${PG_PWD}" + # POSTGRES_DB: trading + # volumes: + # - traderdata:/var/lib/postgresql/data - prometheus: - hostname: prometheus - image: prom/prometheus - container_name: prometheus - ports: - - 9191:9090 - restart: always - volumes: - - ./KLHZ.Trader.Infrastructure/prometheus/:/etc/prometheus/ - - prom_data:/prometheus + # prometheus: + # hostname: prometheus + # image: prom/prometheus + # container_name: prometheus + # ports: + # - 9191:9090 + # restart: always + # volumes: + # - ./KLHZ.Trader.Infrastructure/prometheus/:/etc/prometheus/ + # - prom_data:/prometheus - grafana: - image: grafana/grafana - container_name: grafana - ports: - - 1300:3000 - restart: always - environment: - GF_SECURITY_ADMIN_USER: "${GF_SECURITY_ADMIN_USER}" - GF_SECURITY_ADMIN_PASSWORD: "${GF_SECURITY_ADMIN_PASSWORD}" - volumes: - - graphana:/etc/grafana/provisioning/datasources + # grafana: + # image: grafana/grafana + # container_name: grafana + # ports: + # - 1300:3000 + # restart: always + # environment: + # GF_SECURITY_ADMIN_USER: "${GF_SECURITY_ADMIN_USER}" + # GF_SECURITY_ADMIN_PASSWORD: "${GF_SECURITY_ADMIN_PASSWORD}" + # volumes: + # - graphana:/etc/grafana/provisioning/datasources - loki: - hostname: loki - image: grafana/loki:latest - container_name: loki - restart: always - ports: - - "2300:3100" - volumes: - - ./KLHZ.Trader.Infrastructure/loki/loki-config.yaml:/etc/loki/local-config.yaml - - loki_data:/loki - command: -config.file=/etc/loki/local-config.yaml + # loki: + # hostname: loki + # image: grafana/loki:latest + # container_name: loki + # restart: always + # ports: + # - "2300:3100" + # volumes: + # - ./KLHZ.Trader.Infrastructure/loki/loki-config.yaml:/etc/loki/local-config.yaml + # - loki_data:/loki + # command: -config.file=/etc/loki/local-config.yaml klhz.trader.historyloader: image: klhztraderhistoryloader