diff --git a/KLHZ.Trader.Core/DataLayer/Entities/Experiments/ExperimentsResult.cs b/KLHZ.Trader.Core/DataLayer/Entities/Experiments/ExperimentsResult.cs new file mode 100644 index 0000000..7d0300e --- /dev/null +++ b/KLHZ.Trader.Core/DataLayer/Entities/Experiments/ExperimentsResult.cs @@ -0,0 +1,45 @@ +using KLHZ.Trader.Core.Contracts.Messaging.Dtos; +using KLHZ.Trader.Core.Contracts.Messaging.Dtos.Interfaces; +using System.ComponentModel.DataAnnotations.Schema; + +namespace KLHZ.Trader.Core.DataLayer.Entities.Prices +{ + [Table("experiment_results")] + public class ExperimentsResult : IProcessedPrice + { + [Column("id")] + public long Id { get; set; } + + [Column("time")] + public DateTime Time { get; set; } + + [Column("value")] + public decimal Price { get; set; } + + [Column("figi")] + public required string Figi { get; set; } + + [Column("ticker")] + public required string Ticker { get; set; } + + public bool IsHistoricalData { get; set; } + + [Column("processor")] + public required string Processor { get; set; } + + [NotMapped] + public long Count { get; set; } + + [NotMapped] + public int Direction { get; set; } + + [NotMapped] + public decimal Value { get; set; } + + [NotMapped] + public decimal Value2 { get; set; } + + [NotMapped] + public AttachedInfo? AttachedInfo { get; private set; } + } +} diff --git a/KLHZ.Trader.Core/DataLayer/Entities/Orders/OrderbookElement.cs b/KLHZ.Trader.Core/DataLayer/Entities/Orders/OrderbookElement.cs new file mode 100644 index 0000000..345a8a4 --- /dev/null +++ b/KLHZ.Trader.Core/DataLayer/Entities/Orders/OrderbookElement.cs @@ -0,0 +1,32 @@ +using KLHZ.Trader.Core.Contracts.Messaging.Dtos.Interfaces; +using KLHZ.Trader.Core.DataLayer.Entities.Orders.Enums; +using System.ComponentModel.DataAnnotations.Schema; + +namespace KLHZ.Trader.Core.DataLayer.Entities.Orders +{ + [Table("orderbook_elements")] + public class OrderbookElement : IOrderbookItem + { + [Column("id")] + public long Id { get; set; } + + [Column("time")] + public DateTime Time { get; set; } + + [Column("price")] + public decimal Price { get; set; } + + [Column("count")] + public long Count { get; set; } + + [Column("figi")] + public required string Figi { get; set; } + + [Column("ticker")] + public required string Ticker { get; set; } + + [Column("item_type")] + public OrderbookItemType ItemType { get; set; } + + } +} diff --git a/KLHZ.Trader.Core/DataLayer/Entities/Prices/PriceChange.cs b/KLHZ.Trader.Core/DataLayer/Entities/Prices/PriceChange.cs index 50ea37d..80e35b6 100644 --- a/KLHZ.Trader.Core/DataLayer/Entities/Prices/PriceChange.cs +++ b/KLHZ.Trader.Core/DataLayer/Entities/Prices/PriceChange.cs @@ -1,62 +1,10 @@ -using KLHZ.Trader.Core.Contracts.Messaging.Dtos; -using KLHZ.Trader.Core.Contracts.Messaging.Dtos.Interfaces; -using System.ComponentModel.DataAnnotations.Schema; +using System.ComponentModel.DataAnnotations.Schema; namespace KLHZ.Trader.Core.DataLayer.Entities.Prices { [Table("price_changes")] - public class PriceChange : ITradeDataItem + public class PriceChange : Trade { - [Column("id")] - public long Id { get; set; } - - [Column("time")] - public DateTime Time { get; set; } - - [Column("value")] - public decimal Price { get; set; } - - [Column("figi")] - public required string Figi { get; set; } - - [Column("ticker")] - public required string Ticker { get; set; } - - [NotMapped] - public bool IsHistoricalData { get; set; } - [Column("count")] - public long Count { get; set; } - - [Column("direction")] - public int Direction { get; set; } - - [NotMapped] - public decimal Value { get; set; } - - [NotMapped] - public decimal Value2 { get; set; } - - [NotMapped] - public AttachedInfo? AttachedInfo - { - get - { - lock (_locker) - { - return _attachedInfo; - } - } - } - - public void SetAttachedInfo(AttachedInfo? attachedInfo) - { - lock (_locker) - { - _attachedInfo = attachedInfo; - } - } - - private AttachedInfo? _attachedInfo; - private readonly object _locker = new(); + } } diff --git a/KLHZ.Trader.Core/DataLayer/Entities/Trades/Trade.cs b/KLHZ.Trader.Core/DataLayer/Entities/Trades/Trade.cs new file mode 100644 index 0000000..7bca3ad --- /dev/null +++ b/KLHZ.Trader.Core/DataLayer/Entities/Trades/Trade.cs @@ -0,0 +1,62 @@ +using KLHZ.Trader.Core.Contracts.Messaging.Dtos; +using KLHZ.Trader.Core.Contracts.Messaging.Dtos.Interfaces; +using System.ComponentModel.DataAnnotations.Schema; + +namespace KLHZ.Trader.Core.DataLayer.Entities.Prices +{ + [Table("trades")] + public class Trade : ITradeDataItem + { + [Column("id")] + public long Id { get; set; } + + [Column("time")] + public DateTime Time { get; set; } + + [Column("value")] + public decimal Price { get; set; } + + [Column("figi")] + public required string Figi { get; set; } + + [Column("ticker")] + public required string Ticker { get; set; } + + [NotMapped] + public bool IsHistoricalData { get; set; } + [Column("count")] + public long Count { get; set; } + + [Column("direction")] + public int Direction { get; set; } + + [NotMapped] + public decimal Value { get; set; } + + [NotMapped] + public decimal Value2 { get; set; } + + [NotMapped] + public AttachedInfo? AttachedInfo + { + get + { + lock (_locker) + { + return _attachedInfo; + } + } + } + + public void SetAttachedInfo(AttachedInfo? attachedInfo) + { + lock (_locker) + { + _attachedInfo = attachedInfo; + } + } + + private AttachedInfo? _attachedInfo; + private readonly object _locker = new(); + } +} diff --git a/KLHZ.Trader.Core/DataLayer/TraderDbContext.cs b/KLHZ.Trader.Core/DataLayer/TraderDbContext.cs index f8dd9a0..66222b6 100644 --- a/KLHZ.Trader.Core/DataLayer/TraderDbContext.cs +++ b/KLHZ.Trader.Core/DataLayer/TraderDbContext.cs @@ -9,9 +9,12 @@ namespace KLHZ.Trader.Core.DataLayer public class TraderDbContext : DbContext { public DbSet Declisions { get; set; } + public DbSet Trades { get; set; } public DbSet PriceChanges { get; set; } public DbSet ProcessedPrices { get; set; } + public DbSet ExperimentsResults { get; set; } public DbSet OrderbookItems { get; set; } + public DbSet OrderbookElements { get; set; } public TraderDbContext(DbContextOptions options) : base(options) { @@ -40,6 +43,26 @@ namespace KLHZ.Trader.Core.DataLayer v => DateTime.SpecifyKind(v, DateTimeKind.Utc)); }); + modelBuilder.Entity(entity => + { + entity.HasKey(e1 => new { e1.Time, e1.Id }); + entity.Ignore(e1 => e1.IsHistoricalData); + entity.Property(e => e.Time) + .HasConversion( + v => v.ToUniversalTime(), + v => DateTime.SpecifyKind(v, DateTimeKind.Utc)); + }); + + modelBuilder.Entity(entity => + { + entity.HasKey(e1 => new { e1.Time, e1.Id }); + entity.Ignore(e1 => e1.IsHistoricalData); + entity.Property(e => e.Time) + .HasConversion( + v => v.ToUniversalTime(), + v => DateTime.SpecifyKind(v, DateTimeKind.Utc)); + }); + modelBuilder.Entity(entity => { entity.HasKey(e1 => e1.Id); @@ -49,6 +72,15 @@ namespace KLHZ.Trader.Core.DataLayer v => DateTime.SpecifyKind(v, DateTimeKind.Utc)); }); + modelBuilder.Entity(entity => + { + entity.HasKey(e1 => new { e1.Time, e1.Id }); + entity.Property(e => e.Time) + .HasConversion( + v => v.ToUniversalTime(), + v => DateTime.SpecifyKind(v, DateTimeKind.Utc)); + }); + modelBuilder.Entity(entity => { entity.HasKey(e1 => e1.Id); diff --git a/KLHZ.Trader.Core/Exchange/Services/ExchangeDataReader.cs b/KLHZ.Trader.Core/Exchange/Services/ExchangeDataReader.cs index ca0dda8..ee76758 100644 --- a/KLHZ.Trader.Core/Exchange/Services/ExchangeDataReader.cs +++ b/KLHZ.Trader.Core/Exchange/Services/ExchangeDataReader.cs @@ -13,6 +13,7 @@ using Microsoft.Extensions.Options; using System.Collections.Concurrent; using Tinkoff.InvestApi; using Tinkoff.InvestApi.V1; +using Trade = KLHZ.Trader.Core.DataLayer.Entities.Prices.Trade; namespace KLHZ.Trader.Core.Exchange.Services { @@ -137,14 +138,14 @@ namespace KLHZ.Trader.Core.Exchange.Services }); var lastUpdateDict = new Dictionary(); - var pricesBuffer = new List(); + var pricesBuffer = new List(); var orderbookItemsBuffer = new List(); var lastWrite = DateTime.UtcNow; await foreach (var response in stream.ResponseStream.ReadAllAsync()) { if (response.Trade != null) { - var message = new PriceChange() + var message = new Trade() { Figi = response.Trade.Figi, Ticker = _tradeDataProvider.GetTickerByFigi(response.Trade.Figi), @@ -212,7 +213,7 @@ namespace KLHZ.Trader.Core.Exchange.Services } if (pricesBuffer.Count > 0) { - await context.PriceChanges.AddRangeAsync(pricesBuffer); + await context.Trades.AddRangeAsync(pricesBuffer); pricesBuffer.Clear(); } await context.SaveChangesAsync(); diff --git a/KLHZ.Trader.Service/Controllers/PlayController.cs b/KLHZ.Trader.Service/Controllers/PlayController.cs index d017fb0..da4d7ae 100644 --- a/KLHZ.Trader.Service/Controllers/PlayController.cs +++ b/KLHZ.Trader.Service/Controllers/PlayController.cs @@ -351,5 +351,52 @@ namespace KLHZ.Trader.Service.Controllers } } } + + [HttpGet] + public async Task MigrateData() + { + try + { + + using var context1 = await _dbContextFactory.CreateDbContextAsync(); + context1.ChangeTracker.QueryTrackingBehavior = QueryTrackingBehavior.NoTracking; + var figis = context1.PriceChanges.Select(p => p.Figi).Distinct().ToArray(); + + foreach (var f in figis) + { + try + { + var time1 = new DateTime(2025, 8, 25, 0, 0, 0, DateTimeKind.Utc); + + while (time1 < DateTime.UtcNow) + { + var time2 = time1.AddDays(7); + var prices = await context1.PriceChanges + .Where(c => (c.Figi == f) && c.Time >= time1 && c.Time < time2) + .OrderBy(c => c.Time) + .ToArrayAsync(); + await context1.Trades.AddRangeAsync(prices); + await context1.SaveChangesAsync(); + time1 = time2; + } + } + catch (Exception ex) + { + + } + + } + + + + + + + } + catch (Exception ex) + { + + } + } } }