Обновленная торговля
test / deploy_trader_prod (push) Successful in 5m4s
Details
test / deploy_trader_prod (push) Successful in 5m4s
Details
parent
bbc1b33d84
commit
6940c9f807
|
@ -127,7 +127,7 @@ namespace KLHZ.Trader.Core.Math.Declisions.Utils
|
||||||
}
|
}
|
||||||
|
|
||||||
public static (TradingEvent events, decimal bigWindowAv, decimal smallWindowAv) CheckByWindowAverageMean2(DateTime[] timestamps,
|
public static (TradingEvent events, decimal bigWindowAv, decimal smallWindowAv) CheckByWindowAverageMean2(DateTime[] timestamps,
|
||||||
decimal[] prices, int size, int smallWindow, int bigWindow, TimeSpan timeForUptreandStart,
|
decimal[] prices, int size, int smallWindow, int bigWindow,
|
||||||
decimal uptrendStartingDetectionMeanfullStep = 0m, decimal uptrendEndingDetectionMeanfullStep = 3m)
|
decimal uptrendStartingDetectionMeanfullStep = 0m, decimal uptrendEndingDetectionMeanfullStep = 3m)
|
||||||
{
|
{
|
||||||
var res = TradingEvent.None;
|
var res = TradingEvent.None;
|
||||||
|
@ -182,8 +182,7 @@ namespace KLHZ.Trader.Core.Math.Declisions.Utils
|
||||||
// если фильтрация окном 15 наползает на окно 120 сверху, потенциальное время закрытия лонга и возможно открытия шорта
|
// если фильтрация окном 15 наползает на окно 120 сверху, потенциальное время закрытия лонга и возможно открытия шорта
|
||||||
if (twavss[size - 1] <= twavbs[size - 1] && twavss[size - 2] > twavbs[size - 2])
|
if (twavss[size - 1] <= twavbs[size - 1] && twavss[size - 2] > twavbs[size - 2])
|
||||||
{
|
{
|
||||||
if (pricesForFinalComparison[crossings[0]] - pricesForFinalComparison[crossings[1]] >= uptrendEndingDetectionMeanfullStep
|
if (pricesForFinalComparison[crossings[0]] - pricesForFinalComparison[crossings[1]] >= uptrendEndingDetectionMeanfullStep)
|
||||||
&& times[crossings[0]] - times[crossings[1]] >= timeForUptreandStart)
|
|
||||||
{
|
{
|
||||||
res |= TradingEvent.UptrendEnd;
|
res |= TradingEvent.UptrendEnd;
|
||||||
}
|
}
|
||||||
|
@ -192,8 +191,7 @@ namespace KLHZ.Trader.Core.Math.Declisions.Utils
|
||||||
// если фильтрация окном 120 наползает на окно 15 сверху, потенциальное время открытия лонга и закрытия шорта
|
// если фильтрация окном 120 наползает на окно 15 сверху, потенциальное время открытия лонга и закрытия шорта
|
||||||
if (twavss[size - 1] >= twavbs[size - 1] && twavss[size - 2] < twavbs[size - 2])
|
if (twavss[size - 1] >= twavbs[size - 1] && twavss[size - 2] < twavbs[size - 2])
|
||||||
{
|
{
|
||||||
if (pricesForFinalComparison[crossings[0]] - pricesForFinalComparison[crossings[1]] <= uptrendStartingDetectionMeanfullStep
|
if (pricesForFinalComparison[crossings[0]] - pricesForFinalComparison[crossings[1]] <= uptrendStartingDetectionMeanfullStep)
|
||||||
&& times[crossings[0]] - times[crossings[1]] >= timeForUptreandStart)
|
|
||||||
{
|
{
|
||||||
res |= TradingEvent.UptrendStart;
|
res |= TradingEvent.UptrendStart;
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,5 +12,11 @@
|
||||||
internal const string SmallWindowCrossingAverageProcessor = "Trader_small";
|
internal const string SmallWindowCrossingAverageProcessor = "Trader_small";
|
||||||
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 PowerUppingCoefficient = 1.69m;
|
||||||
|
internal const decimal UppingCoefficient = 1.3m;
|
||||||
|
internal const decimal LowingCoefficient = .77m;
|
||||||
|
internal const decimal PowerLowingCoefficient = .6m;
|
||||||
|
internal const decimal BlockingCoefficient = 0m;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -157,7 +157,7 @@ namespace KLHZ.Trader.Core.Exchange.Services
|
||||||
};
|
};
|
||||||
|
|
||||||
await _tradeDataProvider.AddData(message, TimeSpan.FromHours(7));
|
await _tradeDataProvider.AddData(message, TimeSpan.FromHours(7));
|
||||||
//await _eventBus.Broadcast(message);
|
await _eventBus.Broadcast(message);
|
||||||
|
|
||||||
var exchangeState = ExchangeScheduler.GetCurrentState();
|
var exchangeState = ExchangeScheduler.GetCurrentState();
|
||||||
if (exchangeState == Models.Trading.ExchangeState.ClearingTime
|
if (exchangeState == Models.Trading.ExchangeState.ClearingTime
|
||||||
|
|
|
@ -16,6 +16,7 @@ using Microsoft.Extensions.Hosting;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
using Microsoft.Extensions.Options;
|
using Microsoft.Extensions.Options;
|
||||||
using System.Collections.Concurrent;
|
using System.Collections.Concurrent;
|
||||||
|
using System.Collections.Immutable;
|
||||||
using System.Threading.Channels;
|
using System.Threading.Channels;
|
||||||
using Tinkoff.InvestApi;
|
using Tinkoff.InvestApi;
|
||||||
using Asset = KLHZ.Trader.Core.Exchange.Models.AssetsAccounting.Asset;
|
using Asset = KLHZ.Trader.Core.Exchange.Models.AssetsAccounting.Asset;
|
||||||
|
@ -132,7 +133,8 @@ namespace KLHZ.Trader.Core.Exchange.Services
|
||||||
|
|
||||||
private async Task ProcessPrices()
|
private async Task ProcessPrices()
|
||||||
{
|
{
|
||||||
var pricesCache = new Dictionary<string, List<INewPrice>>();
|
var pricesCache1 = new Dictionary<string, List<INewPrice>>();
|
||||||
|
var pricesCache2 = new Dictionary<string, List<INewPrice>>();
|
||||||
var timesCache = new Dictionary<string, DateTime>();
|
var timesCache = new Dictionary<string, DateTime>();
|
||||||
while (await _pricesChannel.Reader.WaitToReadAsync())
|
while (await _pricesChannel.Reader.WaitToReadAsync())
|
||||||
{
|
{
|
||||||
|
@ -140,14 +142,46 @@ namespace KLHZ.Trader.Core.Exchange.Services
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
#region Ускорение обработки исторических данных при отладке
|
|
||||||
if (message.IsHistoricalData)
|
if (message.IsHistoricalData)
|
||||||
{
|
{
|
||||||
await _tradeDataProvider.AddData(message, TimeSpan.FromHours(6));
|
await _tradeDataProvider.AddData(message, TimeSpan.FromHours(6));
|
||||||
if (!pricesCache.TryGetValue(message.Figi, out var list))
|
}
|
||||||
|
#region Ускорение обработки исторических данных при отладке
|
||||||
|
if (message.Direction == 1)
|
||||||
|
{
|
||||||
|
if (!pricesCache1.TryGetValue(message.Figi, out var list))
|
||||||
{
|
{
|
||||||
list = new List<INewPrice>();
|
list = new List<INewPrice>();
|
||||||
pricesCache[message.Figi] = list;
|
pricesCache1[message.Figi] = list;
|
||||||
|
}
|
||||||
|
list.Add(message);
|
||||||
|
|
||||||
|
if ((list.Last().Time - list.First().Time).TotalSeconds < 0.5)
|
||||||
|
{
|
||||||
|
list.Add(message);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
message = new PriceChange()
|
||||||
|
{
|
||||||
|
Figi = message.Figi,
|
||||||
|
Ticker = message.Ticker,
|
||||||
|
Count = message.Count,
|
||||||
|
Direction = message.Direction,
|
||||||
|
IsHistoricalData = message.IsHistoricalData,
|
||||||
|
Time = message.Time,
|
||||||
|
Value = list.Sum(l => l.Value) / list.Count
|
||||||
|
};
|
||||||
|
list.Clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (message.Direction == 2)
|
||||||
|
{
|
||||||
|
if (!pricesCache2.TryGetValue(message.Figi, out var list))
|
||||||
|
{
|
||||||
|
list = new List<INewPrice>();
|
||||||
|
pricesCache2[message.Figi] = list;
|
||||||
}
|
}
|
||||||
list.Add(message);
|
list.Add(message);
|
||||||
|
|
||||||
|
@ -203,27 +237,6 @@ namespace KLHZ.Trader.Core.Exchange.Services
|
||||||
Value = (decimal)message.Count
|
Value = (decimal)message.Count
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
var sberSells5min = await _tradeDataProvider.GetDataFrom5MinuteWindowCache(message.Figi, Constants._5minSellCacheKey);
|
|
||||||
var sberBuys5min = await _tradeDataProvider.GetDataFrom5MinuteWindowCache(message.Figi, Constants._5minBuyCacheKey);
|
|
||||||
|
|
||||||
var sberSells1min = await _tradeDataProvider.GetDataFrom5MinuteWindowCache(message.Figi, Constants._1minSellCacheKey);
|
|
||||||
var sberBuys1min = await _tradeDataProvider.GetDataFrom5MinuteWindowCache(message.Figi, Constants._1minBuyCacheKey);
|
|
||||||
|
|
||||||
var sells5min = sberSells5min.Sum(s => s.Value);
|
|
||||||
var buys5min = sberBuys5min.Sum(s => s.Value);
|
|
||||||
var sells1min = sberSells1min.Sum(s => s.Value);
|
|
||||||
var buys1min = sberBuys1min.Sum(s => s.Value);
|
|
||||||
|
|
||||||
var su = sells5min + buys5min;
|
|
||||||
if (su != 0)
|
|
||||||
{
|
|
||||||
await LogPrice(message, "sellsbuysbalance", (sells5min / su - 0.5m) * 2);
|
|
||||||
await LogPrice(message, "trades_diff", (buys1min + sells1min) / (su));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
#endregion
|
#endregion
|
||||||
if (_tradingInstrumentsFigis.Contains(message.Figi))
|
if (_tradingInstrumentsFigis.Contains(message.Figi))
|
||||||
|
@ -236,8 +249,67 @@ namespace KLHZ.Trader.Core.Exchange.Services
|
||||||
if ((message.Time - dt).TotalSeconds > 10)
|
if ((message.Time - dt).TotalSeconds > 10)
|
||||||
{
|
{
|
||||||
timesCache[message.Figi] = message.Time;
|
timesCache[message.Figi] = message.Time;
|
||||||
|
var newMod = await CalcTradingMode(message);
|
||||||
|
if (TradingModes.TryGetValue(message.Figi, out var oldMod))
|
||||||
|
{
|
||||||
|
if ((oldMod == TradingMode.Growing || oldMod == TradingMode.Stable)
|
||||||
|
&& oldMod != newMod)
|
||||||
|
{
|
||||||
|
if (!message.IsHistoricalData && BotModeSwitcher.CanSell())
|
||||||
|
{
|
||||||
|
var assetsForClose = _portfolioWrapper.Accounts
|
||||||
|
.SelectMany(a => a.Value.Assets.Values)
|
||||||
|
.Where(a => a.Figi == message.Figi && a.Count > 0)
|
||||||
|
.ToArray();
|
||||||
|
await ClosePositions(assetsForClose, message);
|
||||||
|
}
|
||||||
|
|
||||||
TradingModes[message.Figi] = await CalcTradingMode(message);
|
await LogDeclision(DeclisionTradeAction.CloseLong, message);
|
||||||
|
}
|
||||||
|
if ((oldMod == TradingMode.Dropping || oldMod == TradingMode.SlowDropping)
|
||||||
|
&& oldMod != newMod)
|
||||||
|
{
|
||||||
|
if (!message.IsHistoricalData && BotModeSwitcher.CanPurchase())
|
||||||
|
{
|
||||||
|
var assetsForClose = _portfolioWrapper.Accounts
|
||||||
|
.SelectMany(a => a.Value.Assets.Values)
|
||||||
|
.Where(a => a.Figi == message.Figi && a.Count < 0)
|
||||||
|
.ToArray();
|
||||||
|
await ClosePositions(assetsForClose, message);
|
||||||
|
}
|
||||||
|
await LogDeclision(DeclisionTradeAction.CloseShort, message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (newMod == TradingMode.Growing && newMod != oldMod)
|
||||||
|
{
|
||||||
|
var stops = GetStops(message, PositionType.Long);
|
||||||
|
if (!message.IsHistoricalData && BotModeSwitcher.CanPurchase())
|
||||||
|
{
|
||||||
|
var accounts = _portfolioWrapper.Accounts
|
||||||
|
.Where(a => !a.Value.Assets.ContainsKey(message.Figi))
|
||||||
|
.Take(1)
|
||||||
|
.Select(a => a.Value)
|
||||||
|
.ToArray();
|
||||||
|
await OpenPositions(accounts, message, PositionType.Long, stops.stopLoss, stops.takeProfit, 1);
|
||||||
|
}
|
||||||
|
await LogDeclision(DeclisionTradeAction.OpenLong, message);
|
||||||
|
}
|
||||||
|
if (newMod == TradingMode.Dropping && newMod != oldMod)
|
||||||
|
{
|
||||||
|
var stops = GetStops(message, PositionType.Short);
|
||||||
|
if (!message.IsHistoricalData && BotModeSwitcher.CanSell())
|
||||||
|
{
|
||||||
|
var accounts = _portfolioWrapper.Accounts
|
||||||
|
.Where(a => !a.Value.Assets.ContainsKey(message.Figi))
|
||||||
|
.Take(1)
|
||||||
|
.Select(a => a.Value)
|
||||||
|
.ToArray();
|
||||||
|
await OpenPositions(accounts, message, PositionType.Short, stops.stopLoss, stops.takeProfit, 1);
|
||||||
|
}
|
||||||
|
await LogDeclision(DeclisionTradeAction.OpenShort, message);
|
||||||
|
}
|
||||||
|
TradingModes[message.Figi] = newMod;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -255,31 +327,12 @@ namespace KLHZ.Trader.Core.Exchange.Services
|
||||||
}
|
}
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
if (message.Direction != 1) continue;
|
||||||
ProcessStops(message, currentTime);
|
ProcessStops(message, currentTime);
|
||||||
var windowMaxSize = 2000;
|
var windowMaxSize = 2000;
|
||||||
var data = await _tradeDataProvider.GetData(message.Figi, windowMaxSize);
|
var data = await _tradeDataProvider.GetData(message.Figi, windowMaxSize);
|
||||||
var state = ExchangeScheduler.GetCurrentState(message.Time);
|
var state = ExchangeScheduler.GetCurrentState(message.Time);
|
||||||
|
await ProcessNewPriceIMOEXF3(data, state, message, windowMaxSize);
|
||||||
if (TradingModes[message.Figi] == TradingMode.Stable)
|
|
||||||
{
|
|
||||||
await ProcessNewPriceIMOEXF_Stable(data, state, message, windowMaxSize);
|
|
||||||
}
|
|
||||||
else if (TradingModes[message.Figi] == TradingMode.SlowDropping)
|
|
||||||
{
|
|
||||||
await ProcessNewPriceIMOEXF_Dropping(data, state, message, windowMaxSize, 2);
|
|
||||||
}
|
|
||||||
else if (TradingModes[message.Figi] == TradingMode.Dropping)
|
|
||||||
{
|
|
||||||
await ProcessNewPriceIMOEXF_Dropping(data, state, message, windowMaxSize, 6);
|
|
||||||
}
|
|
||||||
else if (TradingModes[message.Figi] == TradingMode.Growing)
|
|
||||||
{
|
|
||||||
await ProcessNewPriceIMOEXF_Growing(data, state, message, windowMaxSize);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
await ProcessNewPriceIMOEXF2(data, state, message, windowMaxSize);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
|
@ -295,61 +348,28 @@ namespace KLHZ.Trader.Core.Exchange.Services
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task<TradingEvent> CheckByWindowAverageMean((DateTime[] timestamps, decimal[] prices) data,
|
private async Task<Dictionary<TradingEvent, decimal>> GetWindowAverageStartData((DateTime[] timestamps, decimal[] prices) data, int smallWindow, int bigWindow,
|
||||||
INewPrice message, int windowMaxSize, decimal uptrendStartingDetectionMeanfullStep = 0m, decimal uptrendEndingDetectionMeanfullStep = 3m)
|
INewPrice message, int windowMaxSize, decimal uptrendStartingDetectionMeanfullStep = 0m, decimal uptrendEndingDetectionMeanfullStep = 3m, decimal initValue = 1)
|
||||||
{
|
|
||||||
var resultMoveAvFull = MovingAverage.CheckByWindowAverageMean(data.timestamps, data.prices,
|
|
||||||
windowMaxSize, 30, 180, TimeSpan.FromSeconds(20), uptrendStartingDetectionMeanfullStep, uptrendEndingDetectionMeanfullStep);
|
|
||||||
if (resultMoveAvFull.bigWindowAv != 0)
|
|
||||||
{
|
|
||||||
await LogPrice(message, Constants.BigWindowCrossingAverageProcessor, resultMoveAvFull.bigWindowAv);
|
|
||||||
await LogPrice(message, Constants.SmallWindowCrossingAverageProcessor, resultMoveAvFull.smallWindowAv);
|
|
||||||
}
|
|
||||||
return resultMoveAvFull.events;
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task<TradingEvent> CheckByWindowAverageMean2((DateTime[] timestamps, decimal[] prices) data, int smallWindow, int bigWindow,
|
|
||||||
INewPrice message, int windowMaxSize, decimal uptrendStartingDetectionMeanfullStep = 0m, decimal uptrendEndingDetectionMeanfullStep = 3m)
|
|
||||||
{
|
{
|
||||||
var resultMoveAvFull = MovingAverage.CheckByWindowAverageMean2(data.timestamps, data.prices,
|
var resultMoveAvFull = MovingAverage.CheckByWindowAverageMean2(data.timestamps, data.prices,
|
||||||
windowMaxSize, smallWindow, bigWindow, TimeSpan.FromSeconds(20), uptrendStartingDetectionMeanfullStep, uptrendEndingDetectionMeanfullStep);
|
windowMaxSize, smallWindow, bigWindow, uptrendStartingDetectionMeanfullStep, uptrendEndingDetectionMeanfullStep);
|
||||||
if (resultMoveAvFull.bigWindowAv != 0)
|
if (resultMoveAvFull.bigWindowAv != 0)
|
||||||
{
|
{
|
||||||
await LogPrice(message, Constants.BigWindowCrossingAverageProcessor, resultMoveAvFull.bigWindowAv);
|
await LogPrice(message, Constants.BigWindowCrossingAverageProcessor, resultMoveAvFull.bigWindowAv);
|
||||||
await LogPrice(message, Constants.SmallWindowCrossingAverageProcessor, resultMoveAvFull.smallWindowAv);
|
await LogPrice(message, Constants.SmallWindowCrossingAverageProcessor, resultMoveAvFull.smallWindowAv);
|
||||||
}
|
}
|
||||||
return resultMoveAvFull.events;
|
var res = GetInitDict(Constants.PowerLowingCoefficient);
|
||||||
}
|
if ((resultMoveAvFull.events & TradingEvent.UptrendStart) == TradingEvent.UptrendStart)
|
||||||
|
|
||||||
private Task<TradingEvent> CheckByWindowAverageMeanNolog((DateTime[] timestamps, decimal[] prices) data,
|
|
||||||
INewPrice message, int windowMaxSize, decimal uptrendStartingDetectionMeanfullStep = 0m, decimal uptrendEndingDetectionMeanfullStep = 3m)
|
|
||||||
{
|
{
|
||||||
var resultMoveAvFull = MovingAverage.CheckByWindowAverageMean(data.timestamps, data.prices,
|
res[TradingEvent.UptrendStart] = initValue;
|
||||||
windowMaxSize, 30, 180, TimeSpan.FromSeconds(20), uptrendStartingDetectionMeanfullStep, uptrendEndingDetectionMeanfullStep);
|
res[TradingEvent.DowntrendEnd] = initValue;
|
||||||
return Task.FromResult(resultMoveAvFull.events);
|
|
||||||
}
|
}
|
||||||
|
if ((resultMoveAvFull.events & TradingEvent.UptrendEnd) == TradingEvent.UptrendEnd)
|
||||||
private Task<TradingEvent> CheckByWindowAverageMeanForShotrs((DateTime[] timestamps, decimal[] prices) data,
|
|
||||||
INewPrice message, int windowMaxSize)
|
|
||||||
{
|
{
|
||||||
var resultMoveAvFull = MovingAverage.CheckByWindowAverageMean(data.timestamps, data.prices,
|
res[TradingEvent.UptrendEnd] = initValue;
|
||||||
windowMaxSize, 30, 240, TimeSpan.FromSeconds(20), -1m, 1m);
|
res[TradingEvent.DowntrendStart] = initValue;
|
||||||
return Task.FromResult(resultMoveAvFull.events);
|
|
||||||
}
|
}
|
||||||
|
return res;
|
||||||
private Task<TradingEvent> CheckByLocalTrends((DateTime[] timestamps, decimal[] prices) data,
|
|
||||||
INewPrice message, int windowMaxSize)
|
|
||||||
{
|
|
||||||
var res = TradingEvent.None;
|
|
||||||
if (LocalTrends.TryGetLocalTrends(data.timestamps, data.prices, TimeSpan.FromSeconds(60), TimeSpan.FromSeconds(20), 1, out var resLocalTrends))
|
|
||||||
{
|
|
||||||
res |= (resLocalTrends & TradingEvent.UptrendStart);
|
|
||||||
if ((resLocalTrends & TradingEvent.UptrendStart) == TradingEvent.UptrendStart)
|
|
||||||
{
|
|
||||||
res |= TradingEvent.DowntrendEnd;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return Task.FromResult(res);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task<decimal?> GetAreasRelation((DateTime[] timestamps, decimal[] prices) data, INewPrice message)
|
private async Task<decimal?> GetAreasRelation((DateTime[] timestamps, decimal[] prices) data, INewPrice message)
|
||||||
|
@ -378,16 +398,6 @@ namespace KLHZ.Trader.Core.Exchange.Services
|
||||||
return position;
|
return position;
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task<decimal?> CalcTrendDiff(INewPrice message)
|
|
||||||
{
|
|
||||||
var data = await _tradeDataProvider.GetData(message.Figi, TimeSpan.FromHours(1));
|
|
||||||
if (data.isFullIntervalExists && LocalTrends.TryCalcTrendDiff(data.timestamps, data.prices, out var res))
|
|
||||||
{
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task ClosePositions(Asset[] assets, INewPrice message, bool withProfitOnly = true)
|
private async Task ClosePositions(Asset[] assets, INewPrice message, bool withProfitOnly = true)
|
||||||
{
|
{
|
||||||
var loggedDeclisions = 0;
|
var loggedDeclisions = 0;
|
||||||
|
@ -443,7 +453,7 @@ namespace KLHZ.Trader.Core.Exchange.Services
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task ProcessNewPriceIMOEXF2((DateTime[] timestamps, decimal[] prices) data,
|
private async Task ProcessNewPriceIMOEXF3((DateTime[] timestamps, decimal[] prices) data,
|
||||||
ExchangeState state,
|
ExchangeState state,
|
||||||
INewPrice message, int windowMaxSize)
|
INewPrice message, int windowMaxSize)
|
||||||
{
|
{
|
||||||
|
@ -451,41 +461,36 @@ namespace KLHZ.Trader.Core.Exchange.Services
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
//var resTask1 = GetWindowAverageStartData(data, 30, 180, message, windowMaxSize, -2m, 2m,3);
|
||||||
|
var resTask1 = GetWindowAverageStartData(data, 30, 180, message, windowMaxSize, -0.5m, 0.5m, Constants.UppingCoefficient);
|
||||||
|
//var resTask3 = GetWindowAverageStartData(data, 30, 180, message, windowMaxSize, 0, 0,0.7m);
|
||||||
|
var getFFTModsTask = GetFFTMods(message);
|
||||||
|
var getAreasModsTask = GetAreasMods(data, message);
|
||||||
|
var getSellsDiffsModsTask = GetSellsDiffsMods(message);
|
||||||
|
var getTradingModeModsTask = GetTradingModeMods(message);
|
||||||
|
|
||||||
var sberSells = await _tradeDataProvider.GetDataFrom5MinuteWindowCache("BBG004730N88", Constants._1minSellCacheKey);
|
await Task.WhenAll(resTask1, getFFTModsTask, getAreasModsTask, getSellsDiffsModsTask, getTradingModeModsTask);
|
||||||
var sberBuys = await _tradeDataProvider.GetDataFrom5MinuteWindowCache("BBG004730N88", Constants._1minBuyCacheKey);
|
var assetType = _tradeDataProvider.GetAssetTypeByFigi(message.Figi);
|
||||||
var sells = sberSells.Sum(s => s.Value);
|
if (resTask1.Result[TradingEvent.UptrendStart] >= 1)
|
||||||
var buys = sberBuys.Sum(s => s.Value);
|
|
||||||
var su = sells + buys;
|
|
||||||
if (su != 0)
|
|
||||||
{
|
{
|
||||||
var dsell = (sells / su - 0.5m) * 2;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var result = resTask1.Result;
|
||||||
|
|
||||||
|
//result = MergeResults(result, resTask2.Result.ToImmutableDictionary());
|
||||||
|
//result = MergeResults(result, resTask3.Result.ToImmutableDictionary());
|
||||||
|
result = MergeResults(result, getFFTModsTask.Result);
|
||||||
|
result = MergeResults(result, getAreasModsTask.Result);
|
||||||
|
result = MergeResults(result, getSellsDiffsModsTask.Result);
|
||||||
|
result = MergeResults(result, getTradingModeModsTask.Result);
|
||||||
|
|
||||||
var mavTask = CheckByWindowAverageMean(data, message, windowMaxSize, -1, 2m);
|
if (result[TradingEvent.UptrendStart] > Constants.UppingCoefficient
|
||||||
var mavTaskEnds = CheckByWindowAverageMeanNolog(data, message, windowMaxSize, -1, 1m);
|
|
||||||
var mavTaskShorts = CheckByWindowAverageMeanForShotrs(data, message, windowMaxSize);
|
|
||||||
var ltTask = CheckByLocalTrends(data, message, windowMaxSize);
|
|
||||||
var areasTask = GetAreasRelation(data, message);
|
|
||||||
var positionTask = CheckPosition(message);
|
|
||||||
var trendTask = CalcTrendDiff(message);
|
|
||||||
|
|
||||||
var ends = mavTaskEnds.Result & TradingEvent.UptrendEnd;
|
|
||||||
|
|
||||||
await Task.WhenAll(mavTask, ltTask, areasTask, positionTask, trendTask, mavTaskShorts, mavTaskEnds);
|
|
||||||
var assetType = _tradeDataProvider.GetAssetTypeByFigi(message.Figi);
|
|
||||||
var res = mavTask.Result | ltTask.Result;
|
|
||||||
res |= ends;
|
|
||||||
if ((res & TradingEvent.UptrendStart) == TradingEvent.UptrendStart
|
|
||||||
&& !LongOpeningStops.ContainsKey(message.Figi)
|
&& !LongOpeningStops.ContainsKey(message.Figi)
|
||||||
&& trendTask.Result.HasValue
|
|
||||||
&& state == ExchangeState.Open
|
&& state == ExchangeState.Open
|
||||||
&& areasTask.Result.HasValue
|
|
||||||
&& (positionTask.Result == ValueAmplitudePosition.LowerThenMediana)
|
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
|
var stops = GetStops(message, PositionType.Long);
|
||||||
if (!message.IsHistoricalData && BotModeSwitcher.CanPurchase())
|
if (!message.IsHistoricalData && BotModeSwitcher.CanPurchase())
|
||||||
{
|
{
|
||||||
var accounts = _portfolioWrapper.Accounts
|
var accounts = _portfolioWrapper.Accounts
|
||||||
|
@ -493,56 +498,19 @@ namespace KLHZ.Trader.Core.Exchange.Services
|
||||||
.Take(1)
|
.Take(1)
|
||||||
.Select(a => a.Value)
|
.Select(a => a.Value)
|
||||||
.ToArray();
|
.ToArray();
|
||||||
await OpenPositions(accounts, message, PositionType.Long, 7, 10, 1);
|
await OpenPositions(accounts, message, PositionType.Long, stops.stopLoss, stops.takeProfit, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
await LogDeclision(DeclisionTradeAction.OpenLong, message);
|
await LogDeclision(DeclisionTradeAction.OpenLong, message);
|
||||||
|
await LogDeclision(DeclisionTradeAction.OpenLong, message.Value + stops.takeProfit, message.Time.AddMilliseconds(-100), message);
|
||||||
|
await LogDeclision(DeclisionTradeAction.OpenLong, message.Value - stops.stopLoss, message.Time.AddMilliseconds(100), message);
|
||||||
}
|
}
|
||||||
if ((res & TradingEvent.UptrendEnd) == TradingEvent.UptrendEnd)
|
if (result[TradingEvent.DowntrendStart] > Constants.PowerUppingCoefficient
|
||||||
{
|
&& !ShortOpeningStops.ContainsKey(message.Figi)
|
||||||
if (!message.IsHistoricalData && BotModeSwitcher.CanSell())
|
&& state == ExchangeState.Open
|
||||||
{
|
)
|
||||||
var assetsForClose = _portfolioWrapper.Accounts
|
|
||||||
.SelectMany(a => a.Value.Assets.Values)
|
|
||||||
.Where(a => a.Figi == message.Figi && a.Count > 0)
|
|
||||||
.ToArray();
|
|
||||||
await ClosePositions(assetsForClose, message);
|
|
||||||
}
|
|
||||||
await LogDeclision(DeclisionTradeAction.CloseLong, message);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((res & TradingEvent.DowntrendEnd) == TradingEvent.DowntrendEnd)
|
|
||||||
{
|
|
||||||
if (!message.IsHistoricalData && BotModeSwitcher.CanPurchase())
|
|
||||||
{
|
|
||||||
var assetsForClose = _portfolioWrapper.Accounts
|
|
||||||
.SelectMany(a => a.Value.Assets.Values)
|
|
||||||
.Where(a => a.Figi == message.Figi && a.Count < 0)
|
|
||||||
.ToArray();
|
|
||||||
await ClosePositions(assetsForClose, message);
|
|
||||||
}
|
|
||||||
await LogDeclision(DeclisionTradeAction.CloseShort, message);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task ProcessNewPriceIMOEXF_Stable(
|
|
||||||
(DateTime[] timestamps, decimal[] prices) data,
|
|
||||||
ExchangeState state,
|
|
||||||
INewPrice message, int windowMaxSize)
|
|
||||||
{
|
|
||||||
if (data.timestamps.Length <= 4 || state != ExchangeState.Open)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
var mavTask = CheckByWindowAverageMean2(data, 30, 180, message, windowMaxSize, 0, 0);
|
|
||||||
|
|
||||||
await Task.WhenAll(mavTask);
|
|
||||||
var assetType = _tradeDataProvider.GetAssetTypeByFigi(message.Figi);
|
|
||||||
var res = mavTask.Result;
|
|
||||||
|
|
||||||
if ((res & TradingEvent.UptrendStart) == TradingEvent.UptrendStart)
|
|
||||||
{
|
{
|
||||||
|
var stops = GetStops(message, PositionType.Short);
|
||||||
if (!message.IsHistoricalData && BotModeSwitcher.CanPurchase())
|
if (!message.IsHistoricalData && BotModeSwitcher.CanPurchase())
|
||||||
{
|
{
|
||||||
var accounts = _portfolioWrapper.Accounts
|
var accounts = _portfolioWrapper.Accounts
|
||||||
|
@ -550,98 +518,27 @@ namespace KLHZ.Trader.Core.Exchange.Services
|
||||||
.Take(1)
|
.Take(1)
|
||||||
.Select(a => a.Value)
|
.Select(a => a.Value)
|
||||||
.ToArray();
|
.ToArray();
|
||||||
|
await OpenPositions(accounts, message, PositionType.Short, stops.stopLoss, stops.takeProfit, 1);
|
||||||
await OpenPositions(accounts, message, PositionType.Long, 5, 2, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
await LogDeclision(DeclisionTradeAction.OpenLong, message);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task ProcessNewPriceIMOEXF_Growing(
|
|
||||||
(DateTime[] timestamps, decimal[] prices) data,
|
|
||||||
ExchangeState state,
|
|
||||||
INewPrice message, int windowMaxSize)
|
|
||||||
{
|
|
||||||
if (data.timestamps.Length <= 4 || state != ExchangeState.Open)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
var mavTask = CheckByWindowAverageMean2(data, 30, 180, message, windowMaxSize, 0, 0);
|
|
||||||
|
|
||||||
await Task.WhenAll(mavTask);
|
|
||||||
var assetType = _tradeDataProvider.GetAssetTypeByFigi(message.Figi);
|
|
||||||
var res = mavTask.Result;
|
|
||||||
|
|
||||||
if ((res & TradingEvent.UptrendStart) == TradingEvent.UptrendStart)
|
|
||||||
{
|
|
||||||
if (!message.IsHistoricalData && BotModeSwitcher.CanPurchase())
|
|
||||||
{
|
|
||||||
var accounts = _portfolioWrapper.Accounts
|
|
||||||
.Where(a => !a.Value.Assets.ContainsKey(message.Figi))
|
|
||||||
.Take(1)
|
|
||||||
.Select(a => a.Value)
|
|
||||||
.ToArray();
|
|
||||||
|
|
||||||
await OpenPositions(accounts, message, PositionType.Long, 10, 20, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
await LogDeclision(DeclisionTradeAction.OpenLong, message);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((res & TradingEvent.UptrendEnd) == TradingEvent.UptrendEnd)
|
|
||||||
{
|
|
||||||
if (!message.IsHistoricalData && BotModeSwitcher.CanSell())
|
|
||||||
{
|
|
||||||
var assetsForClose = _portfolioWrapper.Accounts
|
|
||||||
.SelectMany(a => a.Value.Assets.Values)
|
|
||||||
.Where(a => a.Figi == message.Figi && a.Count > 0)
|
|
||||||
.ToArray();
|
|
||||||
|
|
||||||
await ClosePositions(assetsForClose, message);
|
|
||||||
}
|
|
||||||
await LogDeclision(DeclisionTradeAction.CloseLong, message);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task ProcessNewPriceIMOEXF_Dropping(
|
|
||||||
(DateTime[] timestamps, decimal[] prices) data,
|
|
||||||
ExchangeState state,
|
|
||||||
INewPrice message, int windowMaxSize, decimal step)
|
|
||||||
{
|
|
||||||
if (data.timestamps.Length <= 4 && state != ExchangeState.Open)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
var mavTask = CheckByWindowAverageMean2(data, 30, 180, message, windowMaxSize, 0, 0);
|
|
||||||
var positionTask = CheckPosition(message);
|
|
||||||
|
|
||||||
await Task.WhenAll(mavTask, positionTask);
|
|
||||||
var assetType = _tradeDataProvider.GetAssetTypeByFigi(message.Figi);
|
|
||||||
var res = mavTask.Result;
|
|
||||||
|
|
||||||
if ((res & TradingEvent.UptrendEnd) == TradingEvent.UptrendEnd && (positionTask.Result != ValueAmplitudePosition.LowerThenMediana))
|
|
||||||
{
|
|
||||||
if (!message.IsHistoricalData && BotModeSwitcher.CanSell())
|
|
||||||
{
|
|
||||||
var accounts = _portfolioWrapper.Accounts
|
|
||||||
.Where(a => !a.Value.Assets.ContainsKey(message.Figi))
|
|
||||||
.Take(1)
|
|
||||||
.Select(a => a.Value)
|
|
||||||
.ToArray();
|
|
||||||
|
|
||||||
|
|
||||||
await OpenPositions(accounts, message, PositionType.Short, 10, 20, 1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
await LogDeclision(DeclisionTradeAction.OpenShort, message);
|
await LogDeclision(DeclisionTradeAction.OpenShort, message);
|
||||||
|
await LogDeclision(DeclisionTradeAction.OpenShort, message.Value - stops.takeProfit, message.Time.AddMilliseconds(-100), message);
|
||||||
|
await LogDeclision(DeclisionTradeAction.OpenShort, message.Value + stops.stopLoss, message.Time.AddMilliseconds(100), message);
|
||||||
|
}
|
||||||
|
if (result[TradingEvent.UptrendEnd] > Constants.UppingCoefficient)
|
||||||
|
{
|
||||||
|
if (!message.IsHistoricalData && BotModeSwitcher.CanSell())
|
||||||
|
{
|
||||||
|
var assetsForClose = _portfolioWrapper.Accounts
|
||||||
|
.SelectMany(a => a.Value.Assets.Values)
|
||||||
|
.Where(a => a.Figi == message.Figi && a.Count > 0)
|
||||||
|
.ToArray();
|
||||||
|
await ClosePositions(assetsForClose, message);
|
||||||
|
}
|
||||||
|
await LogDeclision(DeclisionTradeAction.CloseLong, message);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((res & TradingEvent.UptrendStart) == TradingEvent.UptrendStart)
|
if (result[TradingEvent.DowntrendEnd] > Constants.UppingCoefficient)
|
||||||
{
|
|
||||||
if (!ShortClosingStops.ContainsKey(message.Figi))
|
|
||||||
{
|
{
|
||||||
if (!message.IsHistoricalData && BotModeSwitcher.CanPurchase())
|
if (!message.IsHistoricalData && BotModeSwitcher.CanPurchase())
|
||||||
{
|
{
|
||||||
|
@ -651,15 +548,9 @@ namespace KLHZ.Trader.Core.Exchange.Services
|
||||||
.ToArray();
|
.ToArray();
|
||||||
await ClosePositions(assetsForClose, message);
|
await ClosePositions(assetsForClose, message);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (message.IsHistoricalData)
|
|
||||||
{
|
|
||||||
ShortClosingStops[message.Figi] = message.Time.AddSeconds(30);
|
|
||||||
}
|
|
||||||
await LogDeclision(DeclisionTradeAction.CloseShort, message);
|
await LogDeclision(DeclisionTradeAction.CloseShort, message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
private void ProcessStops(INewPrice message, DateTime currentTime)
|
private void ProcessStops(INewPrice message, DateTime currentTime)
|
||||||
{
|
{
|
||||||
|
@ -719,6 +610,20 @@ namespace KLHZ.Trader.Core.Exchange.Services
|
||||||
}, false);
|
}, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async Task LogDeclision(DeclisionTradeAction action, decimal price, DateTime time, INewPrice message)
|
||||||
|
{
|
||||||
|
await _tradeDataProvider.LogDeclision(new Declision()
|
||||||
|
{
|
||||||
|
AccountId = string.Empty,
|
||||||
|
Figi = message.Figi,
|
||||||
|
Ticker = message.Ticker,
|
||||||
|
Value = price,
|
||||||
|
Price = price,
|
||||||
|
Time = message.IsHistoricalData ? time : DateTime.UtcNow,
|
||||||
|
Action = action,
|
||||||
|
}, false);
|
||||||
|
}
|
||||||
|
|
||||||
public Task StopAsync(CancellationToken cancellationToken)
|
public Task StopAsync(CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
return Task.CompletedTask;
|
return Task.CompletedTask;
|
||||||
|
@ -785,10 +690,189 @@ namespace KLHZ.Trader.Core.Exchange.Services
|
||||||
private async Task<TradingMode> CalcTradingMode(INewPrice message)
|
private async Task<TradingMode> CalcTradingMode(INewPrice message)
|
||||||
{
|
{
|
||||||
var res = await CalcTradingMode(message.Figi);
|
var res = await CalcTradingMode(message.Figi);
|
||||||
//await LogPrice(message, "trading_mode", (int)res);
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private (decimal stopLoss, decimal takeProfit) GetStops(INewPrice message, PositionType type)
|
||||||
|
{
|
||||||
|
var mode = TradingModes[message.Figi];
|
||||||
|
decimal stopLossShift = 5;
|
||||||
|
decimal takeProfitShift = 10;
|
||||||
|
if (mode == TradingMode.Growing && type == PositionType.Long)
|
||||||
|
{
|
||||||
|
stopLossShift = 5;
|
||||||
|
takeProfitShift = 15;
|
||||||
|
}
|
||||||
|
if (mode == TradingMode.Growing && type == PositionType.Short)
|
||||||
|
{
|
||||||
|
stopLossShift = 2;
|
||||||
|
takeProfitShift = 2;
|
||||||
|
}
|
||||||
|
if (mode == TradingMode.Stable && type == PositionType.Long)
|
||||||
|
{
|
||||||
|
stopLossShift = 8;
|
||||||
|
takeProfitShift = 3;
|
||||||
|
}
|
||||||
|
if (mode == TradingMode.Stable && type == PositionType.Short)
|
||||||
|
{
|
||||||
|
stopLossShift = 5;
|
||||||
|
takeProfitShift = 2;
|
||||||
|
}
|
||||||
|
if (mode == TradingMode.SlowDropping && type == PositionType.Short)
|
||||||
|
{
|
||||||
|
stopLossShift = 5;
|
||||||
|
takeProfitShift = 2;
|
||||||
|
}
|
||||||
|
if (mode == TradingMode.SlowDropping && type == PositionType.Long)
|
||||||
|
{
|
||||||
|
stopLossShift = 6;
|
||||||
|
takeProfitShift = 2;
|
||||||
|
}
|
||||||
|
if (mode == TradingMode.Dropping && type == PositionType.Short)
|
||||||
|
{
|
||||||
|
stopLossShift = 10;
|
||||||
|
takeProfitShift = 13;
|
||||||
|
}
|
||||||
|
if (mode == TradingMode.Dropping && type == PositionType.Long)
|
||||||
|
{
|
||||||
|
stopLossShift = 4;
|
||||||
|
takeProfitShift = 2;
|
||||||
|
}
|
||||||
|
return (stopLossShift, takeProfitShift);
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task<ImmutableDictionary<TradingEvent, decimal>> GetFFTMods(INewPrice message)
|
||||||
|
{
|
||||||
|
var res = GetInitDict(1);
|
||||||
|
var position = await CheckPosition(message);
|
||||||
|
|
||||||
|
|
||||||
|
if (position == ValueAmplitudePosition.LowerThenMediana)
|
||||||
|
{
|
||||||
|
res[TradingEvent.UptrendStart] = Constants.UppingCoefficient;
|
||||||
|
res[TradingEvent.DowntrendEnd] = Constants.UppingCoefficient;
|
||||||
|
res[TradingEvent.UptrendEnd] = Constants.LowingCoefficient;
|
||||||
|
res[TradingEvent.DowntrendStart] = Constants.LowingCoefficient;
|
||||||
|
}
|
||||||
|
if (position == ValueAmplitudePosition.UpperThen30Decil)
|
||||||
|
{
|
||||||
|
res[TradingEvent.UptrendStart] = Constants.LowingCoefficient;
|
||||||
|
res[TradingEvent.DowntrendEnd] = Constants.LowingCoefficient;
|
||||||
|
res[TradingEvent.UptrendEnd] = Constants.UppingCoefficient;
|
||||||
|
res[TradingEvent.DowntrendStart] = Constants.UppingCoefficient;
|
||||||
|
}
|
||||||
|
return res.ToImmutableDictionary();
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task<ImmutableDictionary<TradingEvent, decimal>> GetAreasMods((DateTime[] timestamps, decimal[] prices) data, INewPrice message)
|
||||||
|
{
|
||||||
|
var res = GetInitDict(1);
|
||||||
|
var areas = await GetAreasRelation(data, message);
|
||||||
|
if (areas.HasValue && areas.Value > 0.2m && areas.Value <= 0.8m)
|
||||||
|
{
|
||||||
|
res[TradingEvent.UptrendStart] = Constants.LowingCoefficient;
|
||||||
|
}
|
||||||
|
if (areas.HasValue && areas.Value > 0.8m)
|
||||||
|
{
|
||||||
|
//res[TradingEvent.DowntrendStart] = Constants.UppingCoefficient;
|
||||||
|
//res[TradingEvent.DowntrendEnd] = Constants.UppingCoefficient;
|
||||||
|
}
|
||||||
|
return res.ToImmutableDictionary();
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task<ImmutableDictionary<TradingEvent, decimal>> GetSellsDiffsMods(INewPrice message)
|
||||||
|
{
|
||||||
|
var res = GetInitDict(1);
|
||||||
|
var sberSells5min = await _tradeDataProvider.GetDataFrom5MinuteWindowCache("BBG004730N88", Constants._5minSellCacheKey);
|
||||||
|
var sberBuys5min = await _tradeDataProvider.GetDataFrom5MinuteWindowCache("BBG004730N88", Constants._5minBuyCacheKey);
|
||||||
|
|
||||||
|
var sberSells1min = await _tradeDataProvider.GetDataFrom1MinuteWindowCache("BBG004730N88", Constants._1minSellCacheKey);
|
||||||
|
var sberBuys1min = await _tradeDataProvider.GetDataFrom1MinuteWindowCache("BBG004730N88", Constants._1minBuyCacheKey);
|
||||||
|
|
||||||
|
var sells5min = sberSells5min.Sum(s => s.Value);
|
||||||
|
var buys5min = sberBuys5min.Sum(s => s.Value);
|
||||||
|
var sells1min = sberSells1min.Sum(s => s.Value);
|
||||||
|
var buys1min = sberBuys1min.Sum(s => s.Value);
|
||||||
|
|
||||||
|
var su = sells5min + buys5min;
|
||||||
|
var uptrendEndMode = 1m;
|
||||||
|
var downtrendEndMode = 1m;
|
||||||
|
var downstartMode = 1m;
|
||||||
|
var uptrendStartMode = 1m;
|
||||||
|
|
||||||
|
|
||||||
|
if (su != 0)
|
||||||
|
{
|
||||||
|
var trades_rel = (sells5min / su - 0.5m) * 2;
|
||||||
|
var bys_rel = buys1min / su;
|
||||||
|
var sells_rel = sells1min / su;
|
||||||
|
await LogPrice(message, "trades_rel", trades_rel);
|
||||||
|
await LogPrice(message, "bys_rel", bys_rel);
|
||||||
|
await LogPrice(message, "sells_rel", sells_rel);
|
||||||
|
|
||||||
|
if (trades_rel > 0.7m)
|
||||||
|
{
|
||||||
|
uptrendStartMode *= Constants.LowingCoefficient;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (System.Math.Abs(bys_rel) > 0.6m || System.Math.Abs(sells_rel) > 0.6m)
|
||||||
|
{
|
||||||
|
uptrendStartMode *= Constants.UppingCoefficient * Constants.UppingCoefficient;
|
||||||
|
downstartMode *= Constants.UppingCoefficient * Constants.UppingCoefficient;
|
||||||
|
}
|
||||||
|
else if (System.Math.Abs(bys_rel) > 0.3m || System.Math.Abs(sells_rel) > 0.3m)
|
||||||
|
{
|
||||||
|
uptrendStartMode *= Constants.UppingCoefficient;
|
||||||
|
downstartMode *= Constants.UppingCoefficient;
|
||||||
|
}
|
||||||
|
else if (System.Math.Abs(bys_rel) <= 0.2m && System.Math.Abs(sells_rel) <= 0.2m)
|
||||||
|
{
|
||||||
|
uptrendEndMode *= Constants.UppingCoefficient;
|
||||||
|
downtrendEndMode *= Constants.UppingCoefficient;
|
||||||
|
}
|
||||||
|
|
||||||
|
res[TradingEvent.UptrendStart] = uptrendStartMode;
|
||||||
|
res[TradingEvent.UptrendEnd] = uptrendEndMode;
|
||||||
|
res[TradingEvent.DowntrendEnd] = downtrendEndMode;
|
||||||
|
res[TradingEvent.DowntrendStart] = downstartMode;
|
||||||
|
}
|
||||||
|
return res.ToImmutableDictionary();
|
||||||
|
}
|
||||||
|
|
||||||
|
private Task<ImmutableDictionary<TradingEvent, decimal>> GetTradingModeMods(INewPrice message)
|
||||||
|
{
|
||||||
|
var res = GetInitDict(1);
|
||||||
|
var mode = TradingModes[message.Figi];
|
||||||
|
if (mode == TradingMode.Growing)
|
||||||
|
{
|
||||||
|
res[TradingEvent.UptrendEnd] = Constants.PowerLowingCoefficient;
|
||||||
|
res[TradingEvent.UptrendStart] = Constants.UppingCoefficient;
|
||||||
|
res[TradingEvent.DowntrendStart] = Constants.BlockingCoefficient;
|
||||||
|
res[TradingEvent.DowntrendEnd] = Constants.BlockingCoefficient;
|
||||||
|
}
|
||||||
|
if (mode == TradingMode.Stable)
|
||||||
|
{
|
||||||
|
res[TradingEvent.UptrendEnd] = Constants.PowerLowingCoefficient;
|
||||||
|
res[TradingEvent.UptrendStart] = Constants.UppingCoefficient;
|
||||||
|
res[TradingEvent.DowntrendStart] = Constants.BlockingCoefficient;
|
||||||
|
res[TradingEvent.DowntrendEnd] = Constants.UppingCoefficient;
|
||||||
|
}
|
||||||
|
if (mode == TradingMode.SlowDropping)
|
||||||
|
{
|
||||||
|
res[TradingEvent.UptrendStart] = Constants.LowingCoefficient;
|
||||||
|
res[TradingEvent.DowntrendStart] = Constants.UppingCoefficient;
|
||||||
|
res[TradingEvent.DowntrendEnd] = Constants.UppingCoefficient;
|
||||||
|
}
|
||||||
|
if (mode == TradingMode.Dropping)
|
||||||
|
{
|
||||||
|
res[TradingEvent.UptrendEnd] = Constants.PowerUppingCoefficient;
|
||||||
|
res[TradingEvent.UptrendStart] = Constants.BlockingCoefficient;
|
||||||
|
res[TradingEvent.DowntrendStart] = Constants.PowerUppingCoefficient;
|
||||||
|
res[TradingEvent.DowntrendEnd] = Constants.PowerLowingCoefficient;
|
||||||
|
}
|
||||||
|
return Task.FromResult(res.ToImmutableDictionary());
|
||||||
|
}
|
||||||
|
|
||||||
internal static bool IsOperationAllowed(IManagedAccount account, decimal boutPrice, decimal count,
|
internal static bool IsOperationAllowed(IManagedAccount account, decimal boutPrice, decimal count,
|
||||||
decimal accountCashPartFutures, decimal accountCashPart)
|
decimal accountCashPartFutures, decimal accountCashPart)
|
||||||
{
|
{
|
||||||
|
@ -809,5 +893,22 @@ namespace KLHZ.Trader.Core.Exchange.Services
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static Dictionary<TradingEvent, decimal> GetInitDict(decimal initValue)
|
||||||
|
{
|
||||||
|
var values = System.Enum.GetValues<TradingEvent>();
|
||||||
|
return values.ToDictionary(v => v, v => initValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Dictionary<TradingEvent, decimal> MergeResults(Dictionary<TradingEvent, decimal> res, ImmutableDictionary<TradingEvent, decimal> data)
|
||||||
|
{
|
||||||
|
foreach (var k in res.Keys)
|
||||||
|
{
|
||||||
|
var valRes = res[k];
|
||||||
|
var valData = data[k];
|
||||||
|
res[k] = valRes * valData;
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,7 +26,7 @@ namespace KLHZ.Trader.Service.Controllers
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpGet]
|
[HttpGet]
|
||||||
public async Task Run(DateTime? startDate = null)
|
public async Task Run(double? shift = null)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
@ -34,7 +34,7 @@ namespace KLHZ.Trader.Service.Controllers
|
||||||
//var figi1 = "BBG004730N88";
|
//var figi1 = "BBG004730N88";
|
||||||
var figi2 = "BBG004730N88";
|
var figi2 = "BBG004730N88";
|
||||||
//var figi2 = "FUTIMOEXF000";
|
//var figi2 = "FUTIMOEXF000";
|
||||||
var time1 = startDate ?? DateTime.UtcNow.AddDays(-7);
|
var time1 = DateTime.UtcNow.AddDays(-shift ?? -7);
|
||||||
//var time1 = new DateTime(2025, 9, 4, 14, 0, 0, DateTimeKind.Utc);
|
//var time1 = new DateTime(2025, 9, 4, 14, 0, 0, DateTimeKind.Utc);
|
||||||
//var time2 = DateTime.UtcNow.AddMinutes(18);
|
//var time2 = DateTime.UtcNow.AddMinutes(18);
|
||||||
using var context1 = await _dbContextFactory.CreateDbContextAsync();
|
using var context1 = await _dbContextFactory.CreateDbContextAsync();
|
||||||
|
|
Loading…
Reference in New Issue