обновление логики + обновление механизма логирования сделок
test / deploy_trader_prod (push) Successful in 7m30s
Details
test / deploy_trader_prod (push) Successful in 7m30s
Details
parent
c2105ad019
commit
50766b6f20
|
@ -6,5 +6,6 @@
|
|||
|
||||
MarketBuy = 1,
|
||||
MarketSell = 101,
|
||||
LimitBuy = 200,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,5 +7,6 @@
|
|||
public string Figi { get; set; }
|
||||
public string Ticker { get; set; }
|
||||
public DateTime Time { get; set; }
|
||||
public bool IsSellPrice { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
using KLHZ.Trader.Core.Contracts.Messaging.Dtos.Interfaces;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
|
||||
namespace KLHZ.Trader.Core.Contracts.Messaging.Dtos
|
||||
{
|
||||
|
@ -9,5 +10,7 @@ namespace KLHZ.Trader.Core.Contracts.Messaging.Dtos
|
|||
public required string Ticker { get; set; }
|
||||
public DateTime Time { get; set; }
|
||||
public bool IsHistoricalData { get; set; }
|
||||
[NotMapped]
|
||||
public bool IsSellPrice { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -61,7 +61,7 @@ namespace KLHZ.Trader.Core.Math.Declisions.Utils
|
|||
twavbs[i2 + 1]);
|
||||
|
||||
if (shift == 1 && !isCrossing.res) //если нет пересечения скользящих средний с окном 120 и 15 секунд между
|
||||
//текущей и предыдущей точкой - можно не продолжать выполнение.
|
||||
//текущей и предыдущей точкой - можно не продолжать выполнение.
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -211,7 +211,7 @@ namespace KLHZ.Trader.Core.Tests
|
|||
for (int i = 0; i < 5 * PriceHistoryCacheUnit2.CacheMaxLength; i++)
|
||||
{
|
||||
cacheUnit.AddData(new PriceChange() { Figi = "", Ticker = "", Value = i, Time = DateTime.UtcNow });
|
||||
if (i >= 500)
|
||||
if (i >= PriceHistoryCacheUnit2.CacheMaxLength)
|
||||
{
|
||||
var data = cacheUnit.GetData().Result;
|
||||
Assert.IsTrue(data.prices.Length == PriceHistoryCacheUnit2.CacheMaxLength);
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
using KLHZ.Trader.Core.Common;
|
||||
using KLHZ.Trader.Core.Exchange.Models.AssetsAccounting;
|
||||
using KLHZ.Trader.Core.Exchange.Utils;
|
||||
|
||||
namespace KLHZ.Trader.Core.Tests
|
||||
{
|
||||
|
@ -89,5 +90,11 @@ namespace KLHZ.Trader.Core.Tests
|
|||
};
|
||||
Assert.IsTrue(KLHZ.Trader.Core.Exchange.Services.Trader.IsBuyAllowed(account, 3000, 1, 0.5m, 0.1m));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void CalcProfitTest()
|
||||
{
|
||||
var profit = TradingCalculator.CaclProfit(2990, 2991.5m, 0.0025m, 10.3m, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,5 +9,6 @@
|
|||
BidsSummary10 = 4,
|
||||
AsksSummary4 = 5,
|
||||
BidsSummary4 = 6,
|
||||
BidsAsksSummary4 = 7,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -23,5 +23,7 @@ namespace KLHZ.Trader.Core.DataLayer.Entities.Prices
|
|||
|
||||
[NotMapped]
|
||||
public bool IsHistoricalData { get; set; }
|
||||
[NotMapped]
|
||||
public bool IsSellPrice { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -21,10 +21,12 @@ namespace KLHZ.Trader.Core.DataLayer.Entities.Prices
|
|||
[Column("ticker")]
|
||||
public required string Ticker { get; set; }
|
||||
|
||||
[NotMapped]
|
||||
public bool IsHistoricalData { get; set; }
|
||||
|
||||
[Column("processor")]
|
||||
public required string Processor { get; set; }
|
||||
|
||||
[NotMapped]
|
||||
public bool IsSellPrice { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -13,7 +13,6 @@ using Microsoft.Extensions.Logging;
|
|||
using Microsoft.Extensions.Options;
|
||||
using Tinkoff.InvestApi;
|
||||
using Tinkoff.InvestApi.V1;
|
||||
using static Google.Rpc.Context.AttributeContext.Types;
|
||||
|
||||
namespace KLHZ.Trader.Core.Exchange.Services
|
||||
{
|
||||
|
@ -28,6 +27,8 @@ namespace KLHZ.Trader.Core.Exchange.Services
|
|||
private readonly CancellationTokenSource _cts = new();
|
||||
private readonly IDataBus _eventBus;
|
||||
private readonly bool _exchangeDataRecievingEnabled;
|
||||
private readonly SemaphoreSlim _semaphoreSlim = new SemaphoreSlim(1, 1);
|
||||
|
||||
public ExchangeDataReader(InvestApiClient investApiClient, IDataBus eventBus, TraderDataProvider tradeDataProvider,
|
||||
IOptions<ExchangeConfig> options, IDbContextFactory<TraderDbContext> dbContextFactory,
|
||||
ILogger<ExchangeDataReader> logger)
|
||||
|
@ -72,28 +73,30 @@ namespace KLHZ.Trader.Core.Exchange.Services
|
|||
|
||||
private async Task SubscribeMyTrades()
|
||||
{
|
||||
var req = new TradesStreamRequest();
|
||||
var req = new PortfolioStreamRequest();
|
||||
foreach (var a in _tradeDataProvider.Accounts)
|
||||
{
|
||||
req.Accounts.Add(a.Key);
|
||||
}
|
||||
using var stream = _investApiClient.OrdersStream.TradesStream(req);
|
||||
|
||||
using var stream = _investApiClient.OperationsStream.PortfolioStream(req);
|
||||
await foreach (var response in stream.ResponseStream.ReadAllAsync())
|
||||
{
|
||||
if (response.OrderTrades != null)
|
||||
if (response.Portfolio?.Positions != null)
|
||||
{
|
||||
foreach(var t in response.OrderTrades.Trades)
|
||||
if (_semaphoreSlim.CurrentCount == 1)
|
||||
{
|
||||
//await _tradeDataProvider.LogDeal(new Models.AssetsAccounting.DealResult()
|
||||
//{
|
||||
// AccountId = response.OrderTrades.AccountId,
|
||||
// Figi = response.OrderTrades.Figi,
|
||||
// Count = t.Quantity,
|
||||
// Price = t.Price,
|
||||
// Direction = Models.AssetsAccounting.DealDirection
|
||||
//})
|
||||
try
|
||||
{
|
||||
await _semaphoreSlim.WaitAsync(TimeSpan.FromSeconds(5));
|
||||
await _tradeDataProvider.SyncPortfolio(response.Portfolio.AccountId);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
|
||||
}
|
||||
_semaphoreSlim.Release();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -152,6 +155,7 @@ namespace KLHZ.Trader.Core.Exchange.Services
|
|||
Time = response.Trade.Time.ToDateTime().ToUniversalTime(),
|
||||
Value = response.Trade.Price,
|
||||
IsHistoricalData = false,
|
||||
IsSellPrice = response.Trade.Direction == TradeDirection.Sell
|
||||
};
|
||||
await _eventBus.Broadcast(message);
|
||||
|
||||
|
|
|
@ -118,7 +118,7 @@ namespace KLHZ.Trader.Core.Exchange.Services
|
|||
var assetType = _tradeDataProvider.GetAssetTypeByFigi(message.Figi);
|
||||
foreach (var acc in accounts)
|
||||
{
|
||||
var assets = acc.Assets.Values.Where(a => a.Figi == message.Figi && DateTime.UtcNow - a.BoughtAt > TimeSpan.FromHours(4)).ToArray();
|
||||
var assets = acc.Assets.Values.Where(a => a.Figi == message.Figi && (DateTime.UtcNow - a.BoughtAt > TimeSpan.FromHours(4))).ToArray();
|
||||
foreach (var asset in assets)
|
||||
{
|
||||
var profit = TradingCalculator.CaclProfit(asset.BoughtPrice, message.Value,
|
||||
|
|
|
@ -17,6 +17,7 @@ using Tinkoff.InvestApi;
|
|||
using Tinkoff.InvestApi.V1;
|
||||
using Asset = KLHZ.Trader.Core.Exchange.Models.AssetsAccounting.Asset;
|
||||
using AssetType = KLHZ.Trader.Core.Exchange.Models.AssetsAccounting.AssetType;
|
||||
using PositionType = KLHZ.Trader.Core.Exchange.Models.AssetsAccounting.PositionType;
|
||||
|
||||
namespace KLHZ.Trader.Core.Exchange.Services
|
||||
{
|
||||
|
@ -181,6 +182,14 @@ namespace KLHZ.Trader.Core.Exchange.Services
|
|||
return _assetTypesCache.TryGetValue(figi, out var t) ? t : AssetType.Unknown;
|
||||
}
|
||||
|
||||
internal async Task SyncPortfolio(string accountId)
|
||||
{
|
||||
if (Accounts.TryGetValue(accountId, out var account))
|
||||
{
|
||||
await SyncPortfolio(account);
|
||||
}
|
||||
}
|
||||
|
||||
internal async Task SyncPortfolio(ManagedAccount account)
|
||||
{
|
||||
try
|
||||
|
@ -231,6 +240,24 @@ namespace KLHZ.Trader.Core.Exchange.Services
|
|||
#pragma warning restore CS0612 // Тип или член устарел
|
||||
account.Assets.AddOrUpdate(asset.Figi, asset, (k, v) => asset);
|
||||
oldAssets.Remove(asset.Figi);
|
||||
if (trade == null && position.InstrumentType != "currency")
|
||||
{
|
||||
trade = new DataLayer.Entities.Trades.Trade()
|
||||
{
|
||||
AccountId = account.AccountId,
|
||||
Figi = position.Figi,
|
||||
Ticker = position.Ticker,
|
||||
ArchiveStatus = 0,
|
||||
Asset = (DataLayer.Entities.Trades.Enums.AssetType)(int)GetAssetTypeByFigi(position.Figi),
|
||||
BoughtAt = DateTime.UtcNow,
|
||||
Count = position.Quantity,
|
||||
Direction = position.Quantity > 0 ? DataLayer.Entities.Trades.Enums.TradeDirection.Buy : DataLayer.Entities.Trades.Enums.TradeDirection.Sell,
|
||||
Position = position.Quantity > 0 ? DataLayer.Entities.Trades.Enums.PositionType.Long : DataLayer.Entities.Trades.Enums.PositionType.Short,
|
||||
Price = price
|
||||
};
|
||||
await context.Trades.AddAsync(trade);
|
||||
await context.SaveChangesAsync();
|
||||
}
|
||||
}
|
||||
|
||||
account.Total = portfolio.TotalAmountPortfolio;
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
using KLHZ.Trader.Core.Contracts.Messaging.Dtos.Interfaces;
|
||||
using KLHZ.Trader.Core.Contracts.Messaging.Interfaces;
|
||||
using KLHZ.Trader.Core.Exchange.Models.AssetsAccounting;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using System.Threading.Channels;
|
||||
|
@ -42,18 +41,21 @@ namespace KLHZ.Trader.Core.Exchange.Services
|
|||
try
|
||||
{
|
||||
var dir = OrderDirection.Unspecified;
|
||||
var dealDirection = DealDirection.Unknown;
|
||||
var sign = 1;
|
||||
var orderType = OrderType.Unspecified;
|
||||
if (tradeCommand.CommandType == Contracts.Messaging.Dtos.Enums.TradeCommandType.MarketBuy)
|
||||
{
|
||||
dir = OrderDirection.Buy;
|
||||
dealDirection = DealDirection.Buy;
|
||||
orderType = OrderType.Market;
|
||||
}
|
||||
else if (tradeCommand.CommandType == Contracts.Messaging.Dtos.Enums.TradeCommandType.MarketSell)
|
||||
{
|
||||
sign = -1;
|
||||
dir = OrderDirection.Sell;
|
||||
dealDirection = DealDirection.Sell;
|
||||
orderType = OrderType.Market;
|
||||
}
|
||||
else if (tradeCommand.CommandType == Contracts.Messaging.Dtos.Enums.TradeCommandType.LimitBuy && tradeCommand.RecomendPrice.HasValue)
|
||||
{
|
||||
dir = OrderDirection.Buy;
|
||||
orderType = OrderType.Limit;
|
||||
}
|
||||
|
||||
var req = new PostOrderRequest()
|
||||
|
@ -61,23 +63,24 @@ namespace KLHZ.Trader.Core.Exchange.Services
|
|||
AccountId = tradeCommand.AccountId,
|
||||
InstrumentId = tradeCommand.Figi,
|
||||
Direction = dir,
|
||||
OrderType = OrderType.Market,
|
||||
Price = tradeCommand.RecomendPrice ?? 0,
|
||||
OrderType = orderType,
|
||||
Quantity = tradeCommand.Count,
|
||||
ConfirmMarginTrade = tradeCommand.EnableMargin,
|
||||
};
|
||||
|
||||
var res = await _investApiClient.Orders.PostOrderAsync(req);
|
||||
|
||||
var result = new DealResult
|
||||
{
|
||||
Count = sign * res.LotsExecuted,
|
||||
Price = res.ExecutedOrderPrice,
|
||||
Success = true,
|
||||
Direction = dealDirection,
|
||||
AccountId = tradeCommand.AccountId,
|
||||
Figi = tradeCommand.Figi,
|
||||
};
|
||||
await _tradeDataProvider.LogDeal(result);
|
||||
//var result = new DealResult
|
||||
//{
|
||||
// Count = sign * res.LotsExecuted,
|
||||
// Price = res.ExecutedOrderPrice,
|
||||
// Success = true,
|
||||
// Direction = dealDirection,
|
||||
// AccountId = tradeCommand.AccountId,
|
||||
// Figi = tradeCommand.Figi,
|
||||
//};
|
||||
//await _tradeDataProvider.LogDeal(result);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
|
|
Loading…
Reference in New Issue