фиксы новой стратегии
test / deploy_trader_prod (push) Successful in 5m11s
Details
test / deploy_trader_prod (push) Successful in 5m11s
Details
parent
c2612ba85a
commit
022cee9a19
|
@ -56,9 +56,10 @@ namespace KLHZ.Trader.Core.Math.Declisions.Utils
|
|||
}
|
||||
|
||||
public static bool TryCalcTimeWindowsDiff(this ITradeDataItem[] values, TimeSpan boundLeft, TimeSpan boundRight,
|
||||
Func<ITradeDataItem, decimal> fieldSelector, bool calcMean, out decimal result)
|
||||
Func<ITradeDataItem, decimal> fieldSelector, bool calcMean, out decimal result, out decimal resultRelative)
|
||||
{
|
||||
result = default;
|
||||
resultRelative = default;
|
||||
if (values.Length > 1)
|
||||
{
|
||||
var shiftTimeR = values.Last().Time - boundRight;
|
||||
|
@ -78,6 +79,7 @@ namespace KLHZ.Trader.Core.Math.Declisions.Utils
|
|||
valOld = valOld / valuesOld.Length;
|
||||
}
|
||||
result = valNew - valOld;
|
||||
resultRelative = (valNew - valOld) / valOld;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,10 +15,11 @@
|
|||
internal const string AreasRelationProcessor = "balancescalc30min";
|
||||
internal readonly static TimeSpan AreasRelationWindow = TimeSpan.FromMinutes(15);
|
||||
|
||||
internal const decimal ForceExecuteCoefficient = 500000m;
|
||||
internal const decimal PowerUppingCoefficient = 1.69m;
|
||||
internal const decimal UppingCoefficient = 1.3m;
|
||||
internal const decimal LowingCoefficient = .76m;
|
||||
internal const decimal PowerLowingCoefficient = .59m;
|
||||
internal const decimal BlockingCoefficient = 0m;
|
||||
internal const decimal BlockingCoefficient = 0.01m;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,14 @@
|
|||
using KLHZ.Trader.Core.Contracts.Declisions.Dtos.Enums;
|
||||
using KLHZ.Trader.Core.Contracts.Messaging.Dtos.Interfaces;
|
||||
using System.Collections.Immutable;
|
||||
|
||||
namespace KLHZ.Trader.Core.Exchange.Models.Trading
|
||||
{
|
||||
internal class DeferredDeclision
|
||||
{
|
||||
public ImmutableDictionary<TradingEvent, decimal> Events { get; init; } = ImmutableDictionary<TradingEvent, decimal>.Empty;
|
||||
public Stops Stops { get; init; }
|
||||
public DateTime ExpirationTime { get; init; }
|
||||
public required ITradeDataItem Message { get; init; }
|
||||
}
|
||||
}
|
|
@ -6,5 +6,6 @@
|
|||
public decimal Pirson { get; init; }
|
||||
public decimal PriceDiff { get; init; }
|
||||
public decimal TradesDiff { get; init; }
|
||||
public decimal TradesDiffRelative { get; init; }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,5 +6,6 @@
|
|||
public decimal LowValue { get; init; }
|
||||
public decimal HighValue { get; init; }
|
||||
public DateTime? LastLevelTime { get; init; }
|
||||
public DateTime CalculatedAt { get; init; }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -34,9 +34,14 @@ namespace KLHZ.Trader.Core.Exchange.Services
|
|||
|
||||
private readonly ConcurrentDictionary<string, TradingMode> TradingModes = new();
|
||||
|
||||
private readonly ConcurrentDictionary<string, DeferredDeclision> DeferredDeclisions = new();
|
||||
private readonly ConcurrentDictionary<string, SupportLevel[]> SupportLevels = new();
|
||||
private readonly ConcurrentDictionary<string, decimal> DPirsonValues = new();
|
||||
private readonly ConcurrentDictionary<string, decimal> _pirsonValues = new();
|
||||
private readonly ConcurrentDictionary<string, decimal> _dpirsonValues = new();
|
||||
private readonly ConcurrentDictionary<string, DateTime> _supportLevelsCalculationTimes = new();
|
||||
private readonly ConcurrentDictionary<string, DateTime> _usedSupportLevels = new();
|
||||
private readonly ConcurrentDictionary<string, DateTime> _usedSupportLevelsForClosing = new();
|
||||
private readonly ConcurrentDictionary<string, ITradeDataItem> _oldItems = new();
|
||||
|
||||
private readonly Channel<ITradeDataItem> _pricesChannel = Channel.CreateUnbounded<ITradeDataItem>();
|
||||
private readonly Channel<ITradeCommand> _commands = Channel.CreateUnbounded<ITradeCommand>();
|
||||
|
@ -161,44 +166,109 @@ namespace KLHZ.Trader.Core.Exchange.Services
|
|||
{
|
||||
if (message.Figi == "FUTIMOEXF000")
|
||||
{
|
||||
if (DeferredDeclisions.TryGetValue(message.Figi, out var dec))
|
||||
{
|
||||
if (dec.ExpirationTime < message.Time)
|
||||
{
|
||||
if (dec.Events[TradingEvent.OpenShort] > Constants.BlockingCoefficient)
|
||||
{
|
||||
if (dec.Message.Price < message.Price)
|
||||
{
|
||||
var stops2 = GetStops(message);
|
||||
var declisionsStops2 = ProcessStops(stops2, 2m);
|
||||
var e = TraderUtils.MergeResultsMult(dec.Events, declisionsStops2);
|
||||
await ExecuteDeclisions(e.ToImmutableDictionary(), message, stops2, 1);
|
||||
}
|
||||
}
|
||||
else if (dec.Events[TradingEvent.OpenLong] > Constants.BlockingCoefficient)
|
||||
{
|
||||
if (dec.Message.Price > message.Price)
|
||||
{
|
||||
var stops2 = GetStops(message);
|
||||
var declisionsStops2 = ProcessStops(stops2, 2m);
|
||||
var e = TraderUtils.MergeResultsMult(dec.Events, declisionsStops2);
|
||||
await ExecuteDeclisions(e.ToImmutableDictionary(), message, stops2, 1);
|
||||
}
|
||||
}
|
||||
else if (dec.Events[TradingEvent.CloseLong] > Constants.BlockingCoefficient
|
||||
|| dec.Events[TradingEvent.CloseShort] > Constants.BlockingCoefficient)
|
||||
{
|
||||
await ExecuteDeclisions(dec.Events, dec.Message, dec.Stops, 1);
|
||||
}
|
||||
|
||||
DeferredDeclisions.TryRemove(message.Figi, out _);
|
||||
}
|
||||
}
|
||||
|
||||
await CalcSupportLevels(message, 3, 5);
|
||||
var stops = GetStops(message);
|
||||
var pirson = await CalcPirson(message);
|
||||
var declisionPirson = await ProcessPirson(pirson, message);
|
||||
var declisionsSupportLevels = await ProcessSupportLevels(message);
|
||||
var declisionsStops = ProcessStops(stops, 1.5m);
|
||||
var declisionsStops = ProcessStops(stops, 2m);
|
||||
var res = TraderUtils.MergeResultsMult(declisionPirson, declisionsSupportLevels);
|
||||
res = TraderUtils.MergeResultsMult(res, declisionsStops);
|
||||
|
||||
await ExecuteDeclisions(res.ToImmutableDictionary(), message, stops, 1);
|
||||
|
||||
var declision = new DeferredDeclision()
|
||||
{
|
||||
Message = message,
|
||||
Stops = stops,
|
||||
Events = res.ToImmutableDictionary(),
|
||||
ExpirationTime = message.Time.AddSeconds(5)
|
||||
};
|
||||
|
||||
if (declision.Events.Values.Any(v => v > Constants.BlockingCoefficient))
|
||||
{
|
||||
//DeferredDeclisions.TryAdd(message.Figi, declision);
|
||||
}
|
||||
|
||||
_oldItems[message.Figi] = message;
|
||||
}
|
||||
}
|
||||
|
||||
private async Task<ImmutableDictionary<TradingEvent, decimal>> ProcessPirson(PirsonCalculatingResult pirson, ITradeDataItem message)
|
||||
{
|
||||
var res = TraderUtils.GetInitDict(0);
|
||||
if (pirson.Success && DPirsonValues.TryGetValue(message.Figi, out var olddpirs))
|
||||
var res = TraderUtils.GetInitDict(Constants.BlockingCoefficient);
|
||||
if (pirson.Success && _pirsonValues.TryGetValue(message.Figi, out var olddpirs))
|
||||
{
|
||||
if (olddpirs < -0.3m && pirson.Pirson > -0.3m && pirson.PriceDiff > 0 && (pirson.TradesDiff > 0))
|
||||
var dpirson = pirson.Pirson - olddpirs;
|
||||
if (olddpirs < 0 && pirson.Pirson > 0 && pirson.PriceDiff > 0 && (pirson.TradesDiffRelative > 0.2m))
|
||||
{
|
||||
res[TradingEvent.OpenLong] = Constants.PowerUppingCoefficient;
|
||||
await _tradeDataProvider.LogPrice(message, "diffs_pirson_diff_point_long_in", message.Price);
|
||||
}
|
||||
if (olddpirs > 0.3m && pirson.Pirson < 0.3m && pirson.PriceDiff < 0 && (pirson.TradesDiff > 0))
|
||||
//if (olddpirs < -0.7m && pirson.Pirson > -0.7m && pirson.PriceDiff > 0 && (pirson.TradesDiffRelative < -0.1m))
|
||||
//{
|
||||
// res[TradingEvent.OpenLong] = Constants.PowerUppingCoefficient;
|
||||
//}
|
||||
|
||||
if (olddpirs > 0 && pirson.Pirson < 0 && pirson.PriceDiff < 0 && (pirson.TradesDiffRelative > 0.2m))
|
||||
{
|
||||
res[TradingEvent.OpenShort] = Constants.PowerUppingCoefficient;
|
||||
await _tradeDataProvider.LogPrice(message, "diffs_pirson_diff_point_short_in", message.Price);
|
||||
}
|
||||
if (olddpirs > 0.7m && pirson.Pirson < 0.7m)
|
||||
//if (olddpirs > 0.3m && pirson.Pirson < 0.3m && pirson.PriceDiff < 0 && (pirson.TradesDiffRelative > 0.3m))
|
||||
//{
|
||||
// res[TradingEvent.OpenShort] = Constants.PowerUppingCoefficient;
|
||||
//}
|
||||
|
||||
if (_dpirsonValues.TryGetValue(message.Figi, out var oldDprison))
|
||||
{
|
||||
// await _tradeDataProvider.LogPrice(message, "diffs_pirson_diff_point_long_out", message.Price);
|
||||
}
|
||||
if (olddpirs < -0.7m && pirson.Pirson > -0.7m)
|
||||
{
|
||||
// await _tradeDataProvider.LogPrice(message, "diffs_pirson_diff_point_short_out", message.Price);
|
||||
if (oldDprison > 0.02m && dpirson < -0.02m && pirson.Pirson > 0.7m && pirson.TradesDiffRelative < -0.2m)
|
||||
{
|
||||
res[TradingEvent.CloseLong] = Constants.PowerUppingCoefficient;
|
||||
//await _tradeDataProvider.LogPrice(message, "diffs_pirson_diff_point_long_out", message.Price);
|
||||
}
|
||||
if (oldDprison < 0 && dpirson > 0 && pirson.Pirson < -0.6m && pirson.TradesDiffRelative < -0.1m)
|
||||
{
|
||||
res[TradingEvent.CloseShort] = Constants.PowerUppingCoefficient;
|
||||
// await _tradeDataProvider.LogPrice(message, "diffs_pirson_diff_point_short_out", message.Price);
|
||||
}
|
||||
}
|
||||
|
||||
_dpirsonValues[message.Figi] = dpirson;
|
||||
}
|
||||
DPirsonValues[message.Figi] = pirson.Pirson;
|
||||
_pirsonValues[message.Figi] = pirson.Pirson;
|
||||
return res.ToImmutableDictionary();
|
||||
}
|
||||
|
||||
|
@ -212,7 +282,7 @@ namespace KLHZ.Trader.Core.Exchange.Services
|
|||
|
||||
var buys = await _tradeDataProvider.GetDataForTimeWindow(message.Figi, cacheSize, selector: (i) => i.Direction == 1);
|
||||
var trades = await _tradeDataProvider.GetDataForTimeWindow(message.Figi, cacheSize);
|
||||
if (trades.TryCalcTimeWindowsDiff(bigWindow, smallWindow, v => v.Count, false, out var tradesDiff)
|
||||
if (trades.TryCalcTimeWindowsDiff(bigWindow, smallWindow, v => v.Count, false, out var tradesDiff, out var tradesDiffRelative)
|
||||
&& buys.TryCalcTimeDiff(bigWindow, smallWindow, v => v.Price, true, out var pricesDiff))
|
||||
{
|
||||
await _tradeDataProvider.LogPrice(message, "privcesDiff", pricesDiff);
|
||||
|
@ -243,6 +313,7 @@ namespace KLHZ.Trader.Core.Exchange.Services
|
|||
Pirson = res,
|
||||
PriceDiff = pricesDiff,
|
||||
TradesDiff = tradesDiff,
|
||||
TradesDiffRelative = tradesDiffRelative,
|
||||
Success = true,
|
||||
};
|
||||
}
|
||||
|
@ -276,10 +347,10 @@ namespace KLHZ.Trader.Core.Exchange.Services
|
|||
var data = await _tradeDataProvider.GetDataForTimeWindow(message.Figi, TimeSpan.FromHours(depthHours));
|
||||
if (data.Length > 0)
|
||||
{
|
||||
if (data[^1].Time - data[0].Time < TimeSpan.FromHours(depthHours - 1))
|
||||
if (data[^1].Time - data[0].Time < TimeSpan.FromHours(0.5))
|
||||
{
|
||||
data = await _tradeDataProvider.GetDataForTimeWindow(message.Figi, TimeSpan.FromHours(depthHours + 12));
|
||||
if (data[^1].Time - data[0].Time < TimeSpan.FromHours(depthHours - 1))
|
||||
if (data[^1].Time - data[0].Time < TimeSpan.FromHours(0.5))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
@ -305,6 +376,7 @@ namespace KLHZ.Trader.Core.Exchange.Services
|
|||
HighValue = high,
|
||||
LowValue = low,
|
||||
Value = c.Value,
|
||||
CalculatedAt = message.Time,
|
||||
});
|
||||
}
|
||||
else if (last.HighValue >= low && last.HighValue < high)
|
||||
|
@ -313,7 +385,8 @@ namespace KLHZ.Trader.Core.Exchange.Services
|
|||
{
|
||||
LowValue = last.LowValue,
|
||||
HighValue = high,
|
||||
Value = last.LowValue + (high - last.LowValue) / 2
|
||||
Value = last.LowValue + (high - last.LowValue) / 2,
|
||||
CalculatedAt = message.Time,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@ -324,6 +397,7 @@ namespace KLHZ.Trader.Core.Exchange.Services
|
|||
HighValue = high,
|
||||
LowValue = low,
|
||||
Value = c.Value,
|
||||
CalculatedAt = message.Time,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -346,6 +420,7 @@ namespace KLHZ.Trader.Core.Exchange.Services
|
|||
LowValue = level.LowValue,
|
||||
Value = level.Value,
|
||||
LastLevelTime = time,
|
||||
CalculatedAt = message.Time,
|
||||
};
|
||||
i++;
|
||||
}
|
||||
|
@ -426,7 +501,7 @@ namespace KLHZ.Trader.Core.Exchange.Services
|
|||
var sign = positionType == PositionType.Long ? 1 : 1;
|
||||
foreach (var acc in accounts)
|
||||
{
|
||||
if (TraderUtils.IsOperationAllowed(acc, message.Price, 1, _exchangeConfig.AccountCashPartFutures, _exchangeConfig.AccountCashPart))
|
||||
if (TraderUtils.IsOperationAllowed(acc, message.Price, count, _exchangeConfig.AccountCashPartFutures, _exchangeConfig.AccountCashPart))
|
||||
{
|
||||
await acc.OpenPosition(message.Figi, positionType, stopLossShift, takeProfitShift, count);
|
||||
await _dataBus.Broadcast(new MessageForAdmin()
|
||||
|
@ -448,7 +523,7 @@ namespace KLHZ.Trader.Core.Exchange.Services
|
|||
|
||||
private async Task ExecuteDeclisions(ImmutableDictionary<TradingEvent, decimal> result, ITradeDataItem message, Stops st, int accountsForOpening = 1)
|
||||
{
|
||||
var state = ExchangeScheduler.GetCurrentState();
|
||||
var state = ExchangeScheduler.GetCurrentState(message.Time);
|
||||
if (result[TradingEvent.OpenLong] >= Constants.UppingCoefficient
|
||||
&& state == ExchangeState.Open
|
||||
)
|
||||
|
@ -464,15 +539,18 @@ namespace KLHZ.Trader.Core.Exchange.Services
|
|||
.ToArray();
|
||||
await OpenPositions(accounts, message, PositionType.Long, stops.stopLoss, stops.takeProfit, 1);
|
||||
}
|
||||
await _tradeDataProvider.LogDeclision(DeclisionTradeAction.OpenLong, message.Price, message.Time.AddMilliseconds(RandomNumberGenerator.GetInt32(-100, 100)), message);
|
||||
await _tradeDataProvider.LogDeclision(DeclisionTradeAction.ResetStopsLong, message.Price + stops.takeProfit, message.Time.AddMilliseconds(-RandomNumberGenerator.GetInt32(300, 1000)), message);
|
||||
await _tradeDataProvider.LogDeclision(DeclisionTradeAction.ResetStopsLong, message.Price - stops.stopLoss, message.Time.AddMilliseconds(RandomNumberGenerator.GetInt32(300, 1000)), message);
|
||||
var val = message.Price;
|
||||
var valLow = message.Price - stops.stopLoss;
|
||||
var valHigh = message.Price + stops.takeProfit;
|
||||
await _tradeDataProvider.LogDeclision(DeclisionTradeAction.OpenLong, val, message.Time.AddMilliseconds(RandomNumberGenerator.GetInt32(-100, 100)), message);
|
||||
//await _tradeDataProvider.LogDeclision(DeclisionTradeAction.ResetStopsLong, valHigh, message.Time.AddMilliseconds(-RandomNumberGenerator.GetInt32(300, 1000)), message);
|
||||
await _tradeDataProvider.LogDeclision(DeclisionTradeAction.ResetStopsLong, valLow, message.Time.AddMilliseconds(RandomNumberGenerator.GetInt32(300, 1000)), message);
|
||||
}
|
||||
if (result[TradingEvent.OpenShort] >= Constants.UppingCoefficient
|
||||
&& state == ExchangeState.Open
|
||||
)
|
||||
{
|
||||
var stops = st.GetStops(PositionType.Long);
|
||||
var stops = st.GetStops(PositionType.Short);
|
||||
if (!message.IsHistoricalData && BotModeSwitcher.CanPurchase())
|
||||
{
|
||||
var accounts = _portfolioWrapper.Accounts
|
||||
|
@ -482,12 +560,14 @@ namespace KLHZ.Trader.Core.Exchange.Services
|
|||
.ToArray();
|
||||
await OpenPositions(accounts, message, PositionType.Short, stops.stopLoss, stops.takeProfit, 1);
|
||||
}
|
||||
|
||||
await _tradeDataProvider.LogDeclision(DeclisionTradeAction.OpenShort, message.Price, message.Time.AddMilliseconds(RandomNumberGenerator.GetInt32(-100, 100)), message);
|
||||
await _tradeDataProvider.LogDeclision(DeclisionTradeAction.ResetStopsShort, message.Price - stops.takeProfit, message.Time.AddMilliseconds(-RandomNumberGenerator.GetInt32(300, 1000)), message);
|
||||
await _tradeDataProvider.LogDeclision(DeclisionTradeAction.ResetStopsShort, message.Price + stops.stopLoss, message.Time.AddMilliseconds(RandomNumberGenerator.GetInt32(300, 1000)), message);
|
||||
var val = message.Price;
|
||||
var valLow = message.Price - stops.takeProfit;
|
||||
var valHigh = message.Price + stops.stopLoss;
|
||||
await _tradeDataProvider.LogDeclision(DeclisionTradeAction.OpenShort, val, message.Time.AddMilliseconds(RandomNumberGenerator.GetInt32(-100, 100)), message);
|
||||
//await _tradeDataProvider.LogDeclision(DeclisionTradeAction.ResetStopsShort, valLow, message.Time.AddMilliseconds(-RandomNumberGenerator.GetInt32(300, 1000)), message);
|
||||
await _tradeDataProvider.LogDeclision(DeclisionTradeAction.ResetStopsShort, valHigh, message.Time.AddMilliseconds(RandomNumberGenerator.GetInt32(300, 1000)), message);
|
||||
}
|
||||
if (result[TradingEvent.CloseLong] >= Constants.UppingCoefficient * 10)
|
||||
if (result[TradingEvent.CloseLong] >= Constants.UppingCoefficient)
|
||||
{
|
||||
if (!message.IsHistoricalData && BotModeSwitcher.CanSell())
|
||||
{
|
||||
|
@ -501,7 +581,7 @@ namespace KLHZ.Trader.Core.Exchange.Services
|
|||
|
||||
}
|
||||
|
||||
if (result[TradingEvent.CloseShort] >= Constants.UppingCoefficient * 10)
|
||||
if (result[TradingEvent.CloseShort] >= Constants.UppingCoefficient)
|
||||
{
|
||||
if (!message.IsHistoricalData && BotModeSwitcher.CanPurchase())
|
||||
{
|
||||
|
@ -550,10 +630,11 @@ namespace KLHZ.Trader.Core.Exchange.Services
|
|||
|
||||
private Stops GetStops(ITradeDataItem message)
|
||||
{
|
||||
decimal longStopLossShift = message.Value * 0.99m;
|
||||
decimal longTakeProfitShift = message.Value * 1.03m;
|
||||
decimal shortStopLossShift = message.Value * 0.99m;
|
||||
decimal shortTakeProfitShift = message.Value * 1.03m;
|
||||
var additionalShift = message.Price * 0.001m;
|
||||
var longStopLossShift = message.Price * 0.0025m;
|
||||
var longTakeProfitShift = message.Price * 0.02m;
|
||||
var shortStopLossShift = message.Price * 0.0025m;
|
||||
var shortTakeProfitShift = message.Price * 0.02m;
|
||||
if (SupportLevels.TryGetValue(message.Figi, out var levels))
|
||||
{
|
||||
if (levels.Length > 0)
|
||||
|
@ -564,16 +645,29 @@ namespace KLHZ.Trader.Core.Exchange.Services
|
|||
if (message.Price >= levelsByTime[0].LowValue && message.Price < levelsByTime[0].HighValue)
|
||||
{
|
||||
longStopLossShift = message.Price - levelsByTime[0].LowValue;
|
||||
shortStopLossShift = message.Price + levelsByTime[0].HighValue;
|
||||
shortStopLossShift = levelsByTime[0].HighValue - message.Price;
|
||||
}
|
||||
else
|
||||
{
|
||||
var levelsByDiff = levels.Where(l => l.LastLevelTime.HasValue)
|
||||
.OrderBy(l => System.Math.Abs(l.Value - message.Price))
|
||||
var levelsByDiffForLong = levels.Where(l => l.LastLevelTime.HasValue)
|
||||
.OrderBy(l => l.Value - message.Price)
|
||||
.ToArray();
|
||||
var nearestLevel = levelsByDiff[0];
|
||||
longStopLossShift = message.Price - nearestLevel.HighValue;
|
||||
shortStopLossShift = nearestLevel.LowValue - message.Price;
|
||||
|
||||
var levelsByDiffForShort = levels.Where(l => l.LastLevelTime.HasValue)
|
||||
.OrderByDescending(l => l.Value - message.Price)
|
||||
.ToArray();
|
||||
|
||||
var nearestLevel = levelsByDiffForLong[0];
|
||||
if (message.Price > nearestLevel.HighValue)
|
||||
{
|
||||
longStopLossShift = message.Price - nearestLevel.HighValue + additionalShift;
|
||||
}
|
||||
|
||||
nearestLevel = levelsByDiffForShort[0];
|
||||
if (message.Price < nearestLevel.LowValue)
|
||||
{
|
||||
shortStopLossShift = nearestLevel.LowValue - message.Price + additionalShift;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -613,17 +707,69 @@ namespace KLHZ.Trader.Core.Exchange.Services
|
|||
var levelsByTime = levels.Where(l => l.LastLevelTime.HasValue)
|
||||
.OrderByDescending(l => l.LastLevelTime)
|
||||
.ToArray();
|
||||
|
||||
if (message.Price >= levelsByTime[0].LowValue && message.Price < levelsByTime[0].HighValue)
|
||||
var levelByTime = levelsByTime[0];
|
||||
if (message.Price >= levelByTime.LowValue && message.Price < levelByTime.HighValue)
|
||||
{
|
||||
if (message.Price > levelsByTime[0].Value)
|
||||
if (message.Price > levelByTime.Value)
|
||||
{
|
||||
res[TradingEvent.OpenLong] = Constants.BlockingCoefficient;
|
||||
}
|
||||
if (message.Price < levelsByTime[0].Value)
|
||||
if (message.Price < levelByTime.Value)
|
||||
{
|
||||
res[TradingEvent.OpenShort] = Constants.BlockingCoefficient;
|
||||
}
|
||||
if (_oldItems.TryGetValue(message.Figi, out var old1))
|
||||
{
|
||||
var islevelUsed = false;
|
||||
if (_usedSupportLevelsForClosing.TryGetValue(message.Figi, out var time))
|
||||
{
|
||||
if (time == levelByTime.CalculatedAt)
|
||||
{
|
||||
islevelUsed = true;
|
||||
}
|
||||
}
|
||||
if (!islevelUsed)
|
||||
{
|
||||
if (old1.Price < levelByTime.LowValue || levelByTime.CalculatedAt == message.Time)
|
||||
{
|
||||
res[TradingEvent.CloseLong] = Constants.ForceExecuteCoefficient;
|
||||
_usedSupportLevelsForClosing[message.Figi] = levelByTime.CalculatedAt;
|
||||
}
|
||||
if (old1.Price > levelByTime.HighValue || levelByTime.CalculatedAt == message.Time)
|
||||
{
|
||||
res[TradingEvent.CloseShort] = Constants.ForceExecuteCoefficient;
|
||||
_usedSupportLevelsForClosing[message.Figi] = levelByTime.CalculatedAt;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
else if (_oldItems.TryGetValue(message.Figi, out var old))
|
||||
{
|
||||
if (old.Price >= levelByTime.LowValue && old.Price < levelByTime.HighValue)
|
||||
{
|
||||
var islevelUsed = false;
|
||||
if (_usedSupportLevels.TryGetValue(message.Figi, out var time))
|
||||
{
|
||||
if (time == levelByTime.CalculatedAt)
|
||||
{
|
||||
islevelUsed = true;
|
||||
}
|
||||
}
|
||||
if (!islevelUsed)
|
||||
{
|
||||
if (message.Price < levelByTime.LowValue)
|
||||
{
|
||||
res[TradingEvent.OpenShort] = Constants.ForceExecuteCoefficient;
|
||||
_usedSupportLevels[message.Figi] = levelByTime.CalculatedAt;
|
||||
}
|
||||
else if (message.Price > levelByTime.HighValue)
|
||||
{
|
||||
res[TradingEvent.OpenLong] = Constants.ForceExecuteCoefficient;
|
||||
_usedSupportLevels[message.Figi] = levelByTime.CalculatedAt;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -24,6 +24,7 @@ namespace KLHZ.Trader.Core.Exchange.Services
|
|||
private readonly IDbContextFactory<TraderDbContext> _dbContextFactory;
|
||||
private readonly ILogger<TraderDataProvider> _logger;
|
||||
private readonly string[] _instrumentsFigis = [];
|
||||
private readonly string[] _tradingInstrumentsFigis = [];
|
||||
|
||||
public readonly ConcurrentDictionary<string, IOrderbook> Orderbooks = new();
|
||||
private readonly ConcurrentDictionary<string, string> _tickersCache = new();
|
||||
|
@ -40,6 +41,7 @@ namespace KLHZ.Trader.Core.Exchange.Services
|
|||
_dbContextFactory = dbContextFactory;
|
||||
_logger = logger;
|
||||
_instrumentsFigis = options.Value.DataRecievingInstrumentsFigis.ToArray();
|
||||
_tradingInstrumentsFigis = options.Value.TradingInstrumentsFigis.ToArray();
|
||||
_isDataRecievingAllowed = options.Value.ExchangeDataRecievingEnabled;
|
||||
}
|
||||
|
||||
|
@ -142,11 +144,11 @@ namespace KLHZ.Trader.Core.Exchange.Services
|
|||
|
||||
if (_isDataRecievingAllowed)
|
||||
{
|
||||
var time = DateTime.UtcNow.AddHours(-5);
|
||||
var time = DateTime.UtcNow.AddHours(-20);
|
||||
using var context1 = await _dbContextFactory.CreateDbContextAsync();
|
||||
context1.ChangeTracker.QueryTrackingBehavior = QueryTrackingBehavior.NoTracking;
|
||||
var data = await context1.PriceChanges
|
||||
.Where(c => _instrumentsFigis.Contains(c.Figi) && c.Time >= time)
|
||||
.Where(c => _tradingInstrumentsFigis.Contains(c.Figi) && c.Time >= time)
|
||||
.OrderBy(c => c.Time)
|
||||
.Select(c => new TradeDataItem()
|
||||
{
|
||||
|
@ -262,6 +264,7 @@ namespace KLHZ.Trader.Core.Exchange.Services
|
|||
Action = action,
|
||||
}, false);
|
||||
}
|
||||
|
||||
private async Task WritePricesTask()
|
||||
{
|
||||
var buffer1 = new List<ProcessedPrice>();
|
||||
|
|
|
@ -23,10 +23,7 @@ namespace KLHZ.Trader.Core.Exchange.Utils
|
|||
var time = TimeOnly.FromDateTime(dt);
|
||||
if (day == DayOfWeek.Sunday || day == DayOfWeek.Saturday)
|
||||
{
|
||||
if (time > _openTimeHoliday && time < _closeTimeHoliday)
|
||||
{
|
||||
return ExchangeState.Open;
|
||||
}
|
||||
return ExchangeState.Close;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
"Token": "",
|
||||
"ManagingAccountNamePatterns": [ "автотрейд" ],
|
||||
"DataRecievingInstrumentsFigis": [ "BBG004730N88", "FUTIMOEXF000", "FUTGMKN09250", "FUTBR1025000", "FUTNG0925000", "FUTNASD09250" ],
|
||||
"TradingInstrumentsFigis": [ "FUTIMOEXF000", "BBG004730N88" ],
|
||||
"TradingInstrumentsFigis": [ "FUTIMOEXF000"],
|
||||
"FutureComission": 0.0025,
|
||||
"ShareComission": 0.0004,
|
||||
"AccountCashPart": 0.05,
|
||||
|
|
Loading…
Reference in New Issue