docker files fixes from liaqat

This commit is contained in:
alirehmani
2024-05-03 16:39:25 +05:00
commit 464a8730e8
587 changed files with 44288 additions and 0 deletions

View File

@@ -0,0 +1,51 @@
using Managing.Application.Abstractions;
using Managing.Application.Abstractions.Services;
using Managing.Application.Workflows.Flows.Feeds;
using Managing.Application.Workflows.Flows.Trading;
using Managing.Domain.Workflows;
using Managing.Domain.Workflows.Synthetics;
using static Managing.Common.Enums;
namespace Managing.Application.Workflows;
public class FlowFactory : IFlowFactory
{
private readonly IExchangeService _exchangeService;
private readonly ICacheService _cacheService;
private readonly ITradingService _tradingService;
private readonly IAccountService _accountService;
public FlowFactory(IExchangeService exchangeService, ICacheService cacheService, ITradingService tradingService, IAccountService accountService)
{
_exchangeService = exchangeService;
_cacheService = cacheService;
_tradingService = tradingService;
_accountService = accountService;
}
public IFlow BuildFlow(SyntheticFlow request)
{
IFlow flow = request.Type switch
{
FlowType.FeedTicker => new FeedTicker(_exchangeService),
FlowType.RsiDivergence => new RsiDiv(),
FlowType.OpenPosition => new OpenPosition(_exchangeService, _cacheService, _accountService, _tradingService),
_ => throw new NotImplementedException(),
};
flow.Children = new List<IFlow>();
flow.Parameters = new List<FlowParameter>();
foreach (var parameter in request.Parameters)
{
if (!flow.Parameters.Any(p => p.Name == parameter.Name)) {
flow.Parameters.Add(new FlowParameter
{
Name = parameter.Name,
Value = parameter.Value
});
}
}
return flow;
}
}

View File

@@ -0,0 +1,64 @@
using Managing.Application.Abstractions.Services;
using Managing.Domain.Workflows;
using Newtonsoft.Json;
using static Managing.Common.Enums;
namespace Managing.Application.Workflows.Flows.Feeds;
public class FeedTicker : FlowBase
{
public override List<IFlow> Children { get; set; }
public override List<FlowParameter> Parameters { get; set; }
public override Guid ParentId { get; }
public override Guid Id { get; }
public override string Output { get; set; }
public override string Name => "Feed Ticker";
public override FlowType Type => FlowType.FeedTicker;
public override string Description => "This flow will take a feed and output the candles";
public FeedTickerParameters FeedTickerParameters { get; set; }
public override List<FlowOutput> AcceptedInputs => new();
public override List<FlowOutput> OutputTypes => new() { FlowOutput.Candles };
private readonly IExchangeService _exchangeService;
public FeedTicker(IExchangeService exchangeService)
{
_exchangeService = exchangeService;
}
public async override Task Execute(string input)
{
MapParameters();
var candles = await _exchangeService.GetCandlesInflux(FeedTickerParameters.Exchange, FeedTickerParameters.Ticker, DateTime.Now.AddDays(-11), FeedTickerParameters.Timeframe);
Output = JsonConvert.SerializeObject(candles.ToHashSet());
if(Children != null && Children.Count > 0)
{
foreach (var child in Children)
{
await child.Execute(Output);
}
}
}
public override void MapParameters()
{
FeedTickerParameters = new FeedTickerParameters();
foreach (var param in Parameters)
{
if (param.Name == nameof(FeedTickerParameters.Ticker))
FeedTickerParameters.Ticker = (Ticker)Enum.Parse(typeof(Ticker), param.Value);
if (param.Name == nameof(FeedTickerParameters.Exchange))
FeedTickerParameters.Exchange = (TradingExchanges)Enum.Parse(typeof(TradingExchanges), param.Value);
if (param.Name == nameof(FeedTickerParameters.Timeframe))
FeedTickerParameters.Timeframe = (Timeframe)Enum.Parse(typeof(Timeframe), param.Value);
}
}
}
public class FeedTickerParameters
{
public TradingExchanges Exchange { get; set; }
public Ticker Ticker { get; set; }
public Timeframe Timeframe { get; set; }
}

View File

@@ -0,0 +1,65 @@
using Managing.Domain.Candles;
using Managing.Domain.Strategies;
using Managing.Domain.Workflows;
using Newtonsoft.Json;
using static Managing.Common.Enums;
namespace Managing.Application.Workflows.Flows.Feeds;
public class RsiDiv : FlowBase
{
public override List<IFlow> Children { get; set; }
public override List<FlowParameter> Parameters { get; set; }
public override Guid ParentId { get; }
public override Guid Id { get; }
public override string Output { get; set; }
public override string Name => "Rsi Divergence";
public override string Description => "This flow will take a feed of candle an run the RSI Divergence";
public override FlowType Type => FlowType.RsiDivergence;
public override List<FlowOutput> AcceptedInputs => new() { FlowOutput.Candles };
public override List<FlowOutput> OutputTypes => new() { FlowOutput.Signal };
public RsiDivParameters RsiDivParameters { get; set; }
public async override Task Execute(string input)
{
if (string.IsNullOrEmpty(input))
{
throw new ArgumentException($"'{nameof(input)}' cannot be null or empty.", nameof(input));
}
MapParameters();
var candles = JsonConvert.DeserializeObject<HashSet<Candle>>(input);
var strategy = new RSIDivergenceStrategy(Name, RsiDivParameters.Timeframe, RsiDivParameters.Period);
strategy.UpdateCandles(candles);
strategy.Run();
Output = JsonConvert.SerializeObject(strategy.Signals);
if(Children != null && Children.Count > 0)
{
foreach (var child in Children)
{
await child.Execute(Output);
}
}
}
public override void MapParameters()
{
RsiDivParameters = new RsiDivParameters();
foreach (var param in Parameters)
{
if (param.Name == nameof(RsiDivParameters.Period))
RsiDivParameters.Period = int.Parse(param.Value);
if (param.Name == nameof(RsiDivParameters.Timeframe))
RsiDivParameters.Timeframe = (Timeframe)Enum.Parse(typeof(Timeframe), param.Value);
}
}
}
public class RsiDivParameters
{
public int Period { get; set; }
public Timeframe Timeframe { get; set; }
}

View File

@@ -0,0 +1,230 @@
using Managing.Application.Abstractions;
using Managing.Application.Abstractions.Services;
using Managing.Application.Accounts;
using Managing.Application.Shared;
using Managing.Application.Trading.Commands;
using Managing.Application.Trading;
using Managing.Domain.Accounts;
using Managing.Domain.MoneyManagements;
using Managing.Domain.Strategies;
using Managing.Domain.Trades;
using Managing.Domain.Workflows;
using Newtonsoft.Json;
using static Managing.Common.Enums;
using Managing.Domain.Candles;
using Managing.Application.Abstractions.Repositories;
namespace Managing.Application.Workflows.Flows.Trading;
public class OpenPosition : FlowBase
{
public override List<IFlow> Children { get; set; }
public override List<FlowParameter> Parameters { get; set; }
public override Guid ParentId { get; }
public override Guid Id { get; }
public override string Output { get; set; }
public override string Name => "Open Position";
public override FlowType Type => FlowType.OpenPosition;
public override string Description => "This flow will open a position for a given signal";
public OpenPositionParameters OpenPositionParameters { get; set; }
public override List<FlowOutput> AcceptedInputs => new() { FlowOutput.Signal, FlowOutput.MoneyManagement };
public override List<FlowOutput> OutputTypes => new() { FlowOutput.Position };
private readonly IExchangeService _exchangeService;
private readonly ICacheService _cacheService;
private readonly IAccountService _accountService;
private readonly ITradingService _tradingService;
private readonly ISettingsRepository _settingsRepository;
private readonly IMessengerService _messengerService;
private readonly string POSITIONS_KEY = "positions";
private readonly string ACCOUNT_KEY = "account";
private readonly string CANDLES_KEY = "candles";
private readonly string SIGNALS_KEY = "signals";
private readonly string FEE_KEY = "fee";
private readonly string WALLET_BALANCES = "wallet-balance";
private decimal Fee { get; set; }
public OpenPosition(
IExchangeService exchangeService,
ICacheService cacheService,
IAccountService accountService,
ITradingService tradingService)
{
_exchangeService = exchangeService;
_cacheService = cacheService;
_accountService = accountService;
_tradingService = tradingService;
}
public async override Task Execute(string input)
{
MapParameters();
var signal = JsonConvert.DeserializeObject<Signal>(input);
var Candles = JsonConvert.DeserializeObject<HashSet<Candle>>(_cacheService.GetValue(CANDLES_KEY));
var Account = JsonConvert.DeserializeObject<Account>(_cacheService.GetValue(ACCOUNT_KEY));
var Positions = JsonConvert.DeserializeObject<List<Position>>(_cacheService.GetValue(POSITIONS_KEY));
var Signals = JsonConvert.DeserializeObject<HashSet<Signal>>(_cacheService.GetValue(POSITIONS_KEY));
Fee = _cacheService.GetOrSave(FEE_KEY, () =>
{
return _tradingService.GetFee(Account, OpenPositionParameters.IsForBacktest);
}, TimeSpan.FromDays(1));
await ExecuteOpenPosition(signal, Positions, Signals, Candles, Account);
_cacheService.SaveValue(POSITIONS_KEY, JsonConvert.SerializeObject(Positions));
_cacheService.SaveValue(SIGNALS_KEY, JsonConvert.SerializeObject(Signals));
if (Children != null && Children.Count > 0)
{
foreach (var child in Children)
{
await child.Execute(Output);
}
}
}
private async Task ExecuteOpenPosition(Signal signal, List<Position> positions, HashSet<Signal> signals, HashSet<Candle> candles, Account account)
{
// Check if a position is already open
var openedPosition = positions.FirstOrDefault(p => p.Status == PositionStatus.Filled
&& p.SignalIdentifier != signal.Identifier);
var lastPrice = OpenPositionParameters.IsForBacktest ? candles.Last().Close : _exchangeService.GetPrice(account, signal.Ticker, DateTime.UtcNow);
// If position open
if (openedPosition != null)
{
var previousSignal = signals.First(s => s.Identifier == openedPosition.SignalIdentifier);
// Check if signal is the opposite side => flip the position
if (openedPosition.OriginDirection == signal.Direction)
{
// An operation is already open for the same direction
//await LogInformation($"Signal {signal.Identifier} try to open a position but {previousSignal.Identifier} is already open for the same direction");
signals.FirstOrDefault(s => s.Identifier == signal.Identifier).Status = SignalStatus.Expired;
}
else
{
// An operation is already open for the opposite direction
// ==> Flip the position
if (OpenPositionParameters.FlipPosition)
{
//await LogInformation("Try to flip the position because of an opposite direction signal");
//await CloseTrade(previousSignal, openedPosition, openedPosition.Open, lastPrice, true);
positions.FirstOrDefault(s => s.Identifier == previousSignal.Identifier).Status = PositionStatus.Flipped;
await ExecuteOpenPosition(signal, positions, signals, candles, account);
//await LogInformation($"Position {previousSignal.Identifier} flipped by {signal.Identifier} at {lastPrice}$");
}
else
{
//await LogWarning($"A position is already open for signal {previousSignal.Identifier}. Position flipping is currently not enable, the position will not be flipped.");
signals.FirstOrDefault(s => s.Identifier == signal.Identifier).Status = SignalStatus.Expired;
}
}
}
else
{
if (!CanOpenPosition(signal, positions, signals, candles))
{
//await LogInformation("Tried to open position but last position was a loss. Wait for an opposition direction side or wait x candles to open a new position");
signals.FirstOrDefault(s => s.Identifier == signal.Identifier).Status = SignalStatus.Expired;
return;
}
//await LogInformation($"Open position - Date: {signal.Date:T} - SignalIdentifier : {signal.Identifier} - Strategie : {signal.StrategyType}");
try
{
var moneyManagement = await _settingsRepository.GetMoneyManagement(OpenPositionParameters.MoneyManagementName);
var WalletBalances = JsonConvert.DeserializeObject<Dictionary<DateTime, decimal>>(_cacheService.GetValue(WALLET_BALANCES));
var command = new OpenPositionRequest(
OpenPositionParameters.AccountName,
moneyManagement,
signal.Direction,
signal.Ticker,
PositionInitiator.Bot,
signal.Date,
OpenPositionParameters.IsForBacktest,
lastPrice,
balance: WalletBalances.LastOrDefault().Value,
fee: Fee);
var position = await new OpenPositionCommandHandler(_exchangeService, _accountService, _tradingService)
.Handle(command);
if (position != null)
{
if (position.Open.Status != TradeStatus.Cancelled)
{
position.SignalIdentifier = signal.Identifier;
positions.Add(position);
signals.FirstOrDefault(s => s.Identifier == signal.Identifier).Status = SignalStatus.PositionOpen;
if (!OpenPositionParameters.IsForBacktest)
{
await _messengerService.SendPosition(position);
}
Output = JsonConvert.SerializeObject(position);
//Logger.LogInformation($"Position requested");
}
else
{
positions.FirstOrDefault(s => s.Identifier == signal.Identifier).Status = PositionStatus.Rejected;
signals.FirstOrDefault(s => s.Identifier == signal.Identifier).Status = SignalStatus.Expired;
}
}
}
catch (Exception ex)
{
signals.FirstOrDefault(s => s.Identifier == signal.Identifier).Status = SignalStatus.Expired;
//await LogWarning($"Cannot open trade : {ex.Message}");
}
}
}
private bool CanOpenPosition(Signal signal, List<Position> positions, HashSet<Signal> signals, HashSet<Candle> candles)
{
if (positions.Count == 0)
return true;
var lastPosition = positions.LastOrDefault(p => p.IsFinished()
&& p.SignalIdentifier != signal.Identifier
&& p.ProfitAndLoss.Realized < 0
&& p.OriginDirection == signal.Direction);
if (lastPosition == null)
return true;
var tenCandleAgo = candles.TakeLast(10).First();
var positionSignal = signals.FirstOrDefault(s => s.Identifier == lastPosition.SignalIdentifier);
return positionSignal.Date < tenCandleAgo.Date;
}
public override void MapParameters()
{
OpenPositionParameters = new OpenPositionParameters();
foreach (var param in Parameters)
{
if (param.Name == nameof(OpenPositionParameters.AccountName))
OpenPositionParameters.AccountName = param.Value;
if (param.Name == nameof(OpenPositionParameters.MoneyManagementName))
OpenPositionParameters.MoneyManagementName = param.Value;
if (param.Name == nameof(OpenPositionParameters.FlipPosition))
OpenPositionParameters.FlipPosition = bool.Parse(param.Value);
}
}
}
public class OpenPositionParameters
{
public string MoneyManagementName { get; set; }
public string AccountName { get; set; }
public bool IsForBacktest { get; set; }
public bool FlipPosition { get; set; }
}

View File

@@ -0,0 +1,126 @@
using Managing.Application.Abstractions;
using Managing.Application.Abstractions.Repositories;
using Managing.Application.Abstractions.Services;
using Managing.Application.Workflows.Flows.Feeds;
using Managing.Application.Workflows.Flows.Trading;
using Managing.Domain.Workflows;
using Managing.Domain.Workflows.Synthetics;
namespace Managing.Application.Workflows;
public class WorkflowService : IWorkflowService
{
private readonly IWorkflowRepository _workflowRepository;
private readonly IExchangeService _exchangeService;
private readonly IFlowFactory _flowFactory;
private readonly ICacheService _cacheService;
private readonly ITradingService _tradingService;
private readonly IAccountService _accountService;
public WorkflowService(
IWorkflowRepository workflowRepository,
IExchangeService exchangeService,
IFlowFactory flowFactory,
ICacheService cacheService,
ITradingService tradingService,
IAccountService accountService)
{
_workflowRepository = workflowRepository;
_exchangeService = exchangeService;
_flowFactory = flowFactory;
_cacheService = cacheService;
_tradingService = tradingService;
_accountService = accountService;
}
public async Task<Workflow> InsertOrUpdateWorkflow(SyntheticWorkflow workflowRequest)
{
var previousWorkflow = await _workflowRepository.GetWorkflow(workflowRequest.Name);
try
{
if (previousWorkflow != null)
{
await _workflowRepository.UpdateWorkflow(workflowRequest);
}
else
{
await _workflowRepository.InsertWorkflow(workflowRequest);
}
}
catch (Exception ex)
{
throw;
}
return Map(workflowRequest);
}
private Workflow Map(SyntheticWorkflow workflowRequest)
{
var workflow = new Workflow
{
Name = workflowRequest.Name,
Usage = workflowRequest.Usage,
Description = workflowRequest.Description,
Flows = new List<IFlow>()
};
// Add first flow that dont have any parent
var firstFlow = workflowRequest.Flows.SingleOrDefault(f => string.IsNullOrEmpty(f.ParentId));
if (firstFlow != null)
{
var flow = Build(workflowRequest.Flows, firstFlow);
workflow.Flows.Add(flow);
}
else
{
// TODO : Throw exception
throw new Exception("No first flow found");
}
return workflow;
}
private IFlow Build(List<SyntheticFlow> flows, SyntheticFlow firstFlow)
{
var flow = _flowFactory.BuildFlow(firstFlow);
foreach (var flowRequest in flows.Where(f => f.ParentId == firstFlow.Id))
{
flow.Children.Add(Build(flows, flowRequest));
}
return flow;
}
public IEnumerable<SyntheticWorkflow> GetWorkflows()
{
return _workflowRepository.GetWorkflows();
}
public bool DeleteWorkflow(string name)
{
return _workflowRepository.DeleteWorkflow(name);
}
public async Task<Workflow> GetWorkflow(string name)
{
return Map(await _workflowRepository.GetWorkflow(name));
}
public Task<IEnumerable<IFlow>> GetAvailableFlows()
{
var availableFlows = new List<IFlow>
{
new FeedTicker(_exchangeService),
new RsiDiv(),
new OpenPosition(_exchangeService, _cacheService, _accountService, _tradingService)
};
return Task.FromResult(availableFlows.AsEnumerable());
}
}