фиксы новой стратегии
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,
|
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;
|
result = default;
|
||||||
|
resultRelative = default;
|
||||||
if (values.Length > 1)
|
if (values.Length > 1)
|
||||||
{
|
{
|
||||||
var shiftTimeR = values.Last().Time - boundRight;
|
var shiftTimeR = values.Last().Time - boundRight;
|
||||||
|
@ -78,6 +79,7 @@ namespace KLHZ.Trader.Core.Math.Declisions.Utils
|
||||||
valOld = valOld / valuesOld.Length;
|
valOld = valOld / valuesOld.Length;
|
||||||
}
|
}
|
||||||
result = valNew - valOld;
|
result = valNew - valOld;
|
||||||
|
resultRelative = (valNew - valOld) / valOld;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,10 +15,11 @@
|
||||||
internal const string AreasRelationProcessor = "balancescalc30min";
|
internal const string AreasRelationProcessor = "balancescalc30min";
|
||||||
internal readonly static TimeSpan AreasRelationWindow = TimeSpan.FromMinutes(15);
|
internal readonly static TimeSpan AreasRelationWindow = TimeSpan.FromMinutes(15);
|
||||||
|
|
||||||
|
internal const decimal ForceExecuteCoefficient = 500000m;
|
||||||
internal const decimal PowerUppingCoefficient = 1.69m;
|
internal const decimal PowerUppingCoefficient = 1.69m;
|
||||||
internal const decimal UppingCoefficient = 1.3m;
|
internal const decimal UppingCoefficient = 1.3m;
|
||||||
internal const decimal LowingCoefficient = .76m;
|
internal const decimal LowingCoefficient = .76m;
|
||||||
internal const decimal PowerLowingCoefficient = .59m;
|
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 Pirson { get; init; }
|
||||||
public decimal PriceDiff { get; init; }
|
public decimal PriceDiff { get; init; }
|
||||||
public decimal TradesDiff { get; init; }
|
public decimal TradesDiff { get; init; }
|
||||||
|
public decimal TradesDiffRelative { get; init; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,5 +6,6 @@
|
||||||
public decimal LowValue { get; init; }
|
public decimal LowValue { get; init; }
|
||||||
public decimal HighValue { get; init; }
|
public decimal HighValue { get; init; }
|
||||||
public DateTime? LastLevelTime { 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, TradingMode> TradingModes = new();
|
||||||
|
|
||||||
|
private readonly ConcurrentDictionary<string, DeferredDeclision> DeferredDeclisions = new();
|
||||||
private readonly ConcurrentDictionary<string, SupportLevel[]> SupportLevels = 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> _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<ITradeDataItem> _pricesChannel = Channel.CreateUnbounded<ITradeDataItem>();
|
||||||
private readonly Channel<ITradeCommand> _commands = Channel.CreateUnbounded<ITradeCommand>();
|
private readonly Channel<ITradeCommand> _commands = Channel.CreateUnbounded<ITradeCommand>();
|
||||||
|
@ -161,44 +166,109 @@ namespace KLHZ.Trader.Core.Exchange.Services
|
||||||
{
|
{
|
||||||
if (message.Figi == "FUTIMOEXF000")
|
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);
|
await CalcSupportLevels(message, 3, 5);
|
||||||
var stops = GetStops(message);
|
var stops = GetStops(message);
|
||||||
var pirson = await CalcPirson(message);
|
var pirson = await CalcPirson(message);
|
||||||
var declisionPirson = await ProcessPirson(pirson, message);
|
var declisionPirson = await ProcessPirson(pirson, message);
|
||||||
var declisionsSupportLevels = await ProcessSupportLevels(message);
|
var declisionsSupportLevels = await ProcessSupportLevels(message);
|
||||||
var declisionsStops = ProcessStops(stops, 1.5m);
|
var declisionsStops = ProcessStops(stops, 2m);
|
||||||
var res = TraderUtils.MergeResultsMult(declisionPirson, declisionsSupportLevels);
|
var res = TraderUtils.MergeResultsMult(declisionPirson, declisionsSupportLevels);
|
||||||
res = TraderUtils.MergeResultsMult(res, declisionsStops);
|
res = TraderUtils.MergeResultsMult(res, declisionsStops);
|
||||||
|
|
||||||
await ExecuteDeclisions(res.ToImmutableDictionary(), message, stops, 1);
|
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)
|
private async Task<ImmutableDictionary<TradingEvent, decimal>> ProcessPirson(PirsonCalculatingResult pirson, ITradeDataItem message)
|
||||||
{
|
{
|
||||||
var res = TraderUtils.GetInitDict(0);
|
var res = TraderUtils.GetInitDict(Constants.BlockingCoefficient);
|
||||||
if (pirson.Success && DPirsonValues.TryGetValue(message.Figi, out var olddpirs))
|
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;
|
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;
|
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 (oldDprison > 0.02m && dpirson < -0.02m && pirson.Pirson > 0.7m && pirson.TradesDiffRelative < -0.2m)
|
||||||
}
|
{
|
||||||
if (olddpirs < -0.7m && pirson.Pirson > -0.7m)
|
res[TradingEvent.CloseLong] = Constants.PowerUppingCoefficient;
|
||||||
{
|
//await _tradeDataProvider.LogPrice(message, "diffs_pirson_diff_point_long_out", message.Price);
|
||||||
// await _tradeDataProvider.LogPrice(message, "diffs_pirson_diff_point_short_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();
|
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 buys = await _tradeDataProvider.GetDataForTimeWindow(message.Figi, cacheSize, selector: (i) => i.Direction == 1);
|
||||||
var trades = await _tradeDataProvider.GetDataForTimeWindow(message.Figi, cacheSize);
|
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))
|
&& buys.TryCalcTimeDiff(bigWindow, smallWindow, v => v.Price, true, out var pricesDiff))
|
||||||
{
|
{
|
||||||
await _tradeDataProvider.LogPrice(message, "privcesDiff", pricesDiff);
|
await _tradeDataProvider.LogPrice(message, "privcesDiff", pricesDiff);
|
||||||
|
@ -243,6 +313,7 @@ namespace KLHZ.Trader.Core.Exchange.Services
|
||||||
Pirson = res,
|
Pirson = res,
|
||||||
PriceDiff = pricesDiff,
|
PriceDiff = pricesDiff,
|
||||||
TradesDiff = tradesDiff,
|
TradesDiff = tradesDiff,
|
||||||
|
TradesDiffRelative = tradesDiffRelative,
|
||||||
Success = true,
|
Success = true,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -276,10 +347,10 @@ namespace KLHZ.Trader.Core.Exchange.Services
|
||||||
var data = await _tradeDataProvider.GetDataForTimeWindow(message.Figi, TimeSpan.FromHours(depthHours));
|
var data = await _tradeDataProvider.GetDataForTimeWindow(message.Figi, TimeSpan.FromHours(depthHours));
|
||||||
if (data.Length > 0)
|
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));
|
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;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -305,6 +376,7 @@ namespace KLHZ.Trader.Core.Exchange.Services
|
||||||
HighValue = high,
|
HighValue = high,
|
||||||
LowValue = low,
|
LowValue = low,
|
||||||
Value = c.Value,
|
Value = c.Value,
|
||||||
|
CalculatedAt = message.Time,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
else if (last.HighValue >= low && last.HighValue < high)
|
else if (last.HighValue >= low && last.HighValue < high)
|
||||||
|
@ -313,7 +385,8 @@ namespace KLHZ.Trader.Core.Exchange.Services
|
||||||
{
|
{
|
||||||
LowValue = last.LowValue,
|
LowValue = last.LowValue,
|
||||||
HighValue = high,
|
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,
|
HighValue = high,
|
||||||
LowValue = low,
|
LowValue = low,
|
||||||
Value = c.Value,
|
Value = c.Value,
|
||||||
|
CalculatedAt = message.Time,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -346,6 +420,7 @@ namespace KLHZ.Trader.Core.Exchange.Services
|
||||||
LowValue = level.LowValue,
|
LowValue = level.LowValue,
|
||||||
Value = level.Value,
|
Value = level.Value,
|
||||||
LastLevelTime = time,
|
LastLevelTime = time,
|
||||||
|
CalculatedAt = message.Time,
|
||||||
};
|
};
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
|
@ -426,7 +501,7 @@ namespace KLHZ.Trader.Core.Exchange.Services
|
||||||
var sign = positionType == PositionType.Long ? 1 : 1;
|
var sign = positionType == PositionType.Long ? 1 : 1;
|
||||||
foreach (var acc in accounts)
|
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 acc.OpenPosition(message.Figi, positionType, stopLossShift, takeProfitShift, count);
|
||||||
await _dataBus.Broadcast(new MessageForAdmin()
|
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)
|
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
|
if (result[TradingEvent.OpenLong] >= Constants.UppingCoefficient
|
||||||
&& state == ExchangeState.Open
|
&& state == ExchangeState.Open
|
||||||
)
|
)
|
||||||
|
@ -464,15 +539,18 @@ namespace KLHZ.Trader.Core.Exchange.Services
|
||||||
.ToArray();
|
.ToArray();
|
||||||
await OpenPositions(accounts, message, PositionType.Long, stops.stopLoss, stops.takeProfit, 1);
|
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);
|
var val = message.Price;
|
||||||
await _tradeDataProvider.LogDeclision(DeclisionTradeAction.ResetStopsLong, message.Price + stops.takeProfit, message.Time.AddMilliseconds(-RandomNumberGenerator.GetInt32(300, 1000)), message);
|
var valLow = message.Price - stops.stopLoss;
|
||||||
await _tradeDataProvider.LogDeclision(DeclisionTradeAction.ResetStopsLong, message.Price - stops.stopLoss, message.Time.AddMilliseconds(RandomNumberGenerator.GetInt32(300, 1000)), message);
|
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
|
if (result[TradingEvent.OpenShort] >= Constants.UppingCoefficient
|
||||||
&& state == ExchangeState.Open
|
&& state == ExchangeState.Open
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
var stops = st.GetStops(PositionType.Long);
|
var stops = st.GetStops(PositionType.Short);
|
||||||
if (!message.IsHistoricalData && BotModeSwitcher.CanPurchase())
|
if (!message.IsHistoricalData && BotModeSwitcher.CanPurchase())
|
||||||
{
|
{
|
||||||
var accounts = _portfolioWrapper.Accounts
|
var accounts = _portfolioWrapper.Accounts
|
||||||
|
@ -482,12 +560,14 @@ namespace KLHZ.Trader.Core.Exchange.Services
|
||||||
.ToArray();
|
.ToArray();
|
||||||
await OpenPositions(accounts, message, PositionType.Short, stops.stopLoss, stops.takeProfit, 1);
|
await OpenPositions(accounts, message, PositionType.Short, stops.stopLoss, stops.takeProfit, 1);
|
||||||
}
|
}
|
||||||
|
var val = message.Price;
|
||||||
await _tradeDataProvider.LogDeclision(DeclisionTradeAction.OpenShort, message.Price, message.Time.AddMilliseconds(RandomNumberGenerator.GetInt32(-100, 100)), message);
|
var valLow = message.Price - stops.takeProfit;
|
||||||
await _tradeDataProvider.LogDeclision(DeclisionTradeAction.ResetStopsShort, message.Price - stops.takeProfit, message.Time.AddMilliseconds(-RandomNumberGenerator.GetInt32(300, 1000)), message);
|
var valHigh = message.Price + stops.stopLoss;
|
||||||
await _tradeDataProvider.LogDeclision(DeclisionTradeAction.ResetStopsShort, message.Price + stops.stopLoss, message.Time.AddMilliseconds(RandomNumberGenerator.GetInt32(300, 1000)), message);
|
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())
|
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())
|
if (!message.IsHistoricalData && BotModeSwitcher.CanPurchase())
|
||||||
{
|
{
|
||||||
|
@ -550,10 +630,11 @@ namespace KLHZ.Trader.Core.Exchange.Services
|
||||||
|
|
||||||
private Stops GetStops(ITradeDataItem message)
|
private Stops GetStops(ITradeDataItem message)
|
||||||
{
|
{
|
||||||
decimal longStopLossShift = message.Value * 0.99m;
|
var additionalShift = message.Price * 0.001m;
|
||||||
decimal longTakeProfitShift = message.Value * 1.03m;
|
var longStopLossShift = message.Price * 0.0025m;
|
||||||
decimal shortStopLossShift = message.Value * 0.99m;
|
var longTakeProfitShift = message.Price * 0.02m;
|
||||||
decimal shortTakeProfitShift = message.Value * 1.03m;
|
var shortStopLossShift = message.Price * 0.0025m;
|
||||||
|
var shortTakeProfitShift = message.Price * 0.02m;
|
||||||
if (SupportLevels.TryGetValue(message.Figi, out var levels))
|
if (SupportLevels.TryGetValue(message.Figi, out var levels))
|
||||||
{
|
{
|
||||||
if (levels.Length > 0)
|
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)
|
if (message.Price >= levelsByTime[0].LowValue && message.Price < levelsByTime[0].HighValue)
|
||||||
{
|
{
|
||||||
longStopLossShift = message.Price - levelsByTime[0].LowValue;
|
longStopLossShift = message.Price - levelsByTime[0].LowValue;
|
||||||
shortStopLossShift = message.Price + levelsByTime[0].HighValue;
|
shortStopLossShift = levelsByTime[0].HighValue - message.Price;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
var levelsByDiff = levels.Where(l => l.LastLevelTime.HasValue)
|
var levelsByDiffForLong = levels.Where(l => l.LastLevelTime.HasValue)
|
||||||
.OrderBy(l => System.Math.Abs(l.Value - message.Price))
|
.OrderBy(l => l.Value - message.Price)
|
||||||
.ToArray();
|
.ToArray();
|
||||||
var nearestLevel = levelsByDiff[0];
|
|
||||||
longStopLossShift = message.Price - nearestLevel.HighValue;
|
var levelsByDiffForShort = levels.Where(l => l.LastLevelTime.HasValue)
|
||||||
shortStopLossShift = nearestLevel.LowValue - message.Price;
|
.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)
|
var levelsByTime = levels.Where(l => l.LastLevelTime.HasValue)
|
||||||
.OrderByDescending(l => l.LastLevelTime)
|
.OrderByDescending(l => l.LastLevelTime)
|
||||||
.ToArray();
|
.ToArray();
|
||||||
|
var levelByTime = levelsByTime[0];
|
||||||
if (message.Price >= levelsByTime[0].LowValue && message.Price < levelsByTime[0].HighValue)
|
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;
|
res[TradingEvent.OpenLong] = Constants.BlockingCoefficient;
|
||||||
}
|
}
|
||||||
if (message.Price < levelsByTime[0].Value)
|
if (message.Price < levelByTime.Value)
|
||||||
{
|
{
|
||||||
res[TradingEvent.OpenShort] = Constants.BlockingCoefficient;
|
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 IDbContextFactory<TraderDbContext> _dbContextFactory;
|
||||||
private readonly ILogger<TraderDataProvider> _logger;
|
private readonly ILogger<TraderDataProvider> _logger;
|
||||||
private readonly string[] _instrumentsFigis = [];
|
private readonly string[] _instrumentsFigis = [];
|
||||||
|
private readonly string[] _tradingInstrumentsFigis = [];
|
||||||
|
|
||||||
public readonly ConcurrentDictionary<string, IOrderbook> Orderbooks = new();
|
public readonly ConcurrentDictionary<string, IOrderbook> Orderbooks = new();
|
||||||
private readonly ConcurrentDictionary<string, string> _tickersCache = new();
|
private readonly ConcurrentDictionary<string, string> _tickersCache = new();
|
||||||
|
@ -40,6 +41,7 @@ namespace KLHZ.Trader.Core.Exchange.Services
|
||||||
_dbContextFactory = dbContextFactory;
|
_dbContextFactory = dbContextFactory;
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
_instrumentsFigis = options.Value.DataRecievingInstrumentsFigis.ToArray();
|
_instrumentsFigis = options.Value.DataRecievingInstrumentsFigis.ToArray();
|
||||||
|
_tradingInstrumentsFigis = options.Value.TradingInstrumentsFigis.ToArray();
|
||||||
_isDataRecievingAllowed = options.Value.ExchangeDataRecievingEnabled;
|
_isDataRecievingAllowed = options.Value.ExchangeDataRecievingEnabled;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -142,11 +144,11 @@ namespace KLHZ.Trader.Core.Exchange.Services
|
||||||
|
|
||||||
if (_isDataRecievingAllowed)
|
if (_isDataRecievingAllowed)
|
||||||
{
|
{
|
||||||
var time = DateTime.UtcNow.AddHours(-5);
|
var time = DateTime.UtcNow.AddHours(-20);
|
||||||
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.PriceChanges
|
||||||
.Where(c => _instrumentsFigis.Contains(c.Figi) && c.Time >= time)
|
.Where(c => _tradingInstrumentsFigis.Contains(c.Figi) && c.Time >= time)
|
||||||
.OrderBy(c => c.Time)
|
.OrderBy(c => c.Time)
|
||||||
.Select(c => new TradeDataItem()
|
.Select(c => new TradeDataItem()
|
||||||
{
|
{
|
||||||
|
@ -262,6 +264,7 @@ namespace KLHZ.Trader.Core.Exchange.Services
|
||||||
Action = action,
|
Action = action,
|
||||||
}, false);
|
}, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task WritePricesTask()
|
private async Task WritePricesTask()
|
||||||
{
|
{
|
||||||
var buffer1 = new List<ProcessedPrice>();
|
var buffer1 = new List<ProcessedPrice>();
|
||||||
|
|
|
@ -23,10 +23,7 @@ namespace KLHZ.Trader.Core.Exchange.Utils
|
||||||
var time = TimeOnly.FromDateTime(dt);
|
var time = TimeOnly.FromDateTime(dt);
|
||||||
if (day == DayOfWeek.Sunday || day == DayOfWeek.Saturday)
|
if (day == DayOfWeek.Sunday || day == DayOfWeek.Saturday)
|
||||||
{
|
{
|
||||||
if (time > _openTimeHoliday && time < _closeTimeHoliday)
|
return ExchangeState.Close;
|
||||||
{
|
|
||||||
return ExchangeState.Open;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
|
@ -12,7 +12,7 @@
|
||||||
"Token": "",
|
"Token": "",
|
||||||
"ManagingAccountNamePatterns": [ "автотрейд" ],
|
"ManagingAccountNamePatterns": [ "автотрейд" ],
|
||||||
"DataRecievingInstrumentsFigis": [ "BBG004730N88", "FUTIMOEXF000", "FUTGMKN09250", "FUTBR1025000", "FUTNG0925000", "FUTNASD09250" ],
|
"DataRecievingInstrumentsFigis": [ "BBG004730N88", "FUTIMOEXF000", "FUTGMKN09250", "FUTBR1025000", "FUTNG0925000", "FUTNASD09250" ],
|
||||||
"TradingInstrumentsFigis": [ "FUTIMOEXF000", "BBG004730N88" ],
|
"TradingInstrumentsFigis": [ "FUTIMOEXF000"],
|
||||||
"FutureComission": 0.0025,
|
"FutureComission": 0.0025,
|
||||||
"ShareComission": 0.0004,
|
"ShareComission": 0.0004,
|
||||||
"AccountCashPart": 0.05,
|
"AccountCashPart": 0.05,
|
||||||
|
|
Loading…
Reference in New Issue