Orlean (#32)
* Start building with orlean * Add missing file * Serialize grain state * Remove grain and proxies * update and add plan * Update a bit * Fix backtest grain * Fix backtest grain * Clean a bit
This commit is contained in:
@@ -1,17 +1,32 @@
|
||||
using Managing.Domain.Users;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using Managing.Domain.Users;
|
||||
using Orleans;
|
||||
using static Managing.Common.Enums;
|
||||
|
||||
namespace Managing.Domain.Accounts;
|
||||
|
||||
[GenerateSerializer]
|
||||
public class Account
|
||||
{
|
||||
[Id(0)]
|
||||
[Required] public string Name { get; set; }
|
||||
|
||||
[Id(1)]
|
||||
[Required] public TradingExchanges Exchange { get; set; }
|
||||
|
||||
[Id(2)]
|
||||
[Required] public AccountType Type { get; set; }
|
||||
|
||||
[Id(3)]
|
||||
public string Key { get; set; }
|
||||
|
||||
[Id(4)]
|
||||
public string Secret { get; set; }
|
||||
|
||||
[Id(5)]
|
||||
public User User { get; set; }
|
||||
|
||||
[Id(6)]
|
||||
public List<Balance> Balances { get; set; }
|
||||
|
||||
public bool IsPrivyWallet => Type == AccountType.Privy;
|
||||
|
||||
@@ -1,14 +1,29 @@
|
||||
using Managing.Domain.Evm;
|
||||
using Orleans;
|
||||
|
||||
namespace Managing.Domain.Accounts;
|
||||
|
||||
[GenerateSerializer]
|
||||
public class Balance
|
||||
{
|
||||
[Id(0)]
|
||||
public string TokenImage { get; set; }
|
||||
|
||||
[Id(1)]
|
||||
public string TokenName { get; set; }
|
||||
|
||||
[Id(2)]
|
||||
public decimal Amount { get; set; }
|
||||
|
||||
[Id(3)]
|
||||
public decimal Price { get; set; }
|
||||
|
||||
[Id(4)]
|
||||
public decimal Value { get; set; }
|
||||
|
||||
[Id(5)]
|
||||
public string TokenAdress { get; set; }
|
||||
|
||||
[Id(6)]
|
||||
public Chain Chain { get; set; }
|
||||
}
|
||||
@@ -1,20 +1,26 @@
|
||||
using Managing.Domain.Bots;
|
||||
using Orleans;
|
||||
|
||||
namespace Managing.Domain.Backtests;
|
||||
|
||||
/// <summary>
|
||||
/// Lightweight backtest class for Orleans serialization
|
||||
/// Contains only the essential properties needed for backtest results
|
||||
/// </summary>
|
||||
[GenerateSerializer]
|
||||
public class LightBacktest
|
||||
{
|
||||
public string Id { get; set; } = string.Empty;
|
||||
public TradingBotConfig Config { get; set; } = new();
|
||||
public decimal FinalPnl { get; set; }
|
||||
public int WinRate { get; set; }
|
||||
public decimal GrowthPercentage { get; set; }
|
||||
public decimal HodlPercentage { get; set; }
|
||||
public DateTime StartDate { get; set; }
|
||||
public DateTime EndDate { get; set; }
|
||||
public decimal? MaxDrawdown { get; set; }
|
||||
public decimal Fees { get; set; }
|
||||
public double? SharpeRatio { get; set; }
|
||||
public double Score { get; set; }
|
||||
public string ScoreMessage { get; set; } = string.Empty;
|
||||
[Id(0)] public string Id { get; set; } = string.Empty;
|
||||
[Id(1)] public TradingBotConfig Config { get; set; } = new();
|
||||
[Id(2)] public decimal FinalPnl { get; set; }
|
||||
[Id(3)] public int WinRate { get; set; }
|
||||
[Id(4)] public decimal GrowthPercentage { get; set; }
|
||||
[Id(5)] public decimal HodlPercentage { get; set; }
|
||||
[Id(6)] public DateTime StartDate { get; set; }
|
||||
[Id(7)] public DateTime EndDate { get; set; }
|
||||
[Id(8)] public decimal? MaxDrawdown { get; set; }
|
||||
[Id(9)] public decimal Fees { get; set; }
|
||||
[Id(10)] public double? SharpeRatio { get; set; }
|
||||
[Id(11)] public double Score { get; set; }
|
||||
[Id(12)] public string ScoreMessage { get; set; } = string.Empty;
|
||||
}
|
||||
@@ -1,15 +1,26 @@
|
||||
using Managing.Domain.Users;
|
||||
using Newtonsoft.Json;
|
||||
using Orleans;
|
||||
using static Managing.Common.Enums;
|
||||
|
||||
namespace Managing.Domain.Bots;
|
||||
|
||||
[GenerateSerializer]
|
||||
public class BotBackup
|
||||
{
|
||||
[Id(0)]
|
||||
public string Identifier { get; set; }
|
||||
|
||||
[Id(1)]
|
||||
public User User { get; set; }
|
||||
|
||||
[Id(2)]
|
||||
public TradingBotBackup Data { get; set; }
|
||||
|
||||
[Id(3)]
|
||||
public BotStatus LastStatus { get; set; }
|
||||
|
||||
[Id(4)]
|
||||
public DateTime CreateDate { get; set; }
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -1,36 +1,44 @@
|
||||
using Managing.Domain.Trades;
|
||||
using Orleans;
|
||||
|
||||
namespace Managing.Domain.Bots;
|
||||
|
||||
[GenerateSerializer]
|
||||
public class TradingBotBackup
|
||||
{
|
||||
/// <summary>
|
||||
/// The complete trading bot configuration
|
||||
/// </summary>
|
||||
[Id(0)]
|
||||
public TradingBotConfig Config { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Runtime state: Active signals for the bot
|
||||
/// </summary>
|
||||
[Id(1)]
|
||||
public HashSet<LightSignal> Signals { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Runtime state: Open and closed positions for the bot
|
||||
/// </summary>
|
||||
[Id(2)]
|
||||
public List<Position> Positions { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Runtime state: Historical wallet balances over time
|
||||
/// </summary>
|
||||
[Id(3)]
|
||||
public Dictionary<DateTime, decimal> WalletBalances { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Runtime state: When the bot was started
|
||||
/// </summary>
|
||||
[Id(4)]
|
||||
public DateTime StartupTime { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Runtime state: When the bot was created
|
||||
/// </summary>
|
||||
[Id(5)]
|
||||
public DateTime CreateDate { get; set; }
|
||||
}
|
||||
@@ -1,22 +1,45 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using Managing.Domain.Risk;
|
||||
using Managing.Domain.Scenarios;
|
||||
using Orleans;
|
||||
using static Managing.Common.Enums;
|
||||
|
||||
namespace Managing.Domain.Bots;
|
||||
|
||||
[GenerateSerializer]
|
||||
public class TradingBotConfig
|
||||
{
|
||||
[Id(0)]
|
||||
[Required] public string AccountName { get; set; }
|
||||
|
||||
[Id(1)]
|
||||
[Required] public LightMoneyManagement MoneyManagement { get; set; }
|
||||
|
||||
[Id(2)]
|
||||
[Required] public Ticker Ticker { get; set; }
|
||||
|
||||
[Id(3)]
|
||||
[Required] public Timeframe Timeframe { get; set; }
|
||||
|
||||
[Id(4)]
|
||||
[Required] public bool IsForWatchingOnly { get; set; }
|
||||
|
||||
[Id(5)]
|
||||
[Required] public decimal BotTradingBalance { get; set; }
|
||||
|
||||
[Id(6)]
|
||||
[Required] public bool IsForBacktest { get; set; }
|
||||
|
||||
[Id(7)]
|
||||
[Required] public int CooldownPeriod { get; set; }
|
||||
|
||||
[Id(8)]
|
||||
[Required] public int MaxLossStreak { get; set; }
|
||||
|
||||
[Id(9)]
|
||||
[Required] public bool FlipPosition { get; set; }
|
||||
|
||||
[Id(10)]
|
||||
[Required] public string Name { get; set; }
|
||||
|
||||
/// <summary>
|
||||
@@ -24,23 +47,28 @@ public class TradingBotConfig
|
||||
/// Contains all configurable parameters for Expected Utility Theory, Kelly Criterion, and probability thresholds.
|
||||
/// If null, default risk management settings will be used.
|
||||
/// </summary>
|
||||
[Id(11)]
|
||||
public RiskManagement RiskManagement { get; set; } = new();
|
||||
|
||||
/// <summary>
|
||||
/// The scenario object containing all strategies. When provided, this takes precedence over ScenarioName.
|
||||
/// The lightweight scenario object containing all strategies. When provided, this takes precedence over ScenarioName.
|
||||
/// This allows running backtests without requiring scenarios to be saved in the database.
|
||||
/// Orleans-friendly version without FixedSizeQueue and User properties.
|
||||
/// </summary>
|
||||
public Scenario Scenario { get; set; }
|
||||
[Id(12)]
|
||||
public LightScenario Scenario { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The scenario name to load from database. Only used when Scenario object is not provided.
|
||||
/// </summary>
|
||||
[Id(13)]
|
||||
public string ScenarioName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Maximum time in hours that a position can remain open before being automatically closed.
|
||||
/// If null, time-based position closure is disabled.
|
||||
/// </summary>
|
||||
[Id(14)]
|
||||
public decimal? MaxPositionTimeHours { get; set; }
|
||||
|
||||
/// <summary>
|
||||
@@ -49,6 +77,7 @@ public class TradingBotConfig
|
||||
/// If false, the position will only be closed when MaxPositionTimeHours is reached.
|
||||
/// Default is false to maintain existing behavior.
|
||||
/// </summary>
|
||||
[Id(15)]
|
||||
public bool CloseEarlyWhenProfitable { get; set; } = false;
|
||||
|
||||
/// <summary>
|
||||
@@ -56,6 +85,7 @@ public class TradingBotConfig
|
||||
/// If false, positions will be flipped regardless of profit status.
|
||||
/// Default is true for safer trading.
|
||||
/// </summary>
|
||||
[Id(16)]
|
||||
[Required]
|
||||
public bool FlipOnlyWhenInProfit { get; set; } = true;
|
||||
|
||||
@@ -65,20 +95,24 @@ public class TradingBotConfig
|
||||
/// When false, the bot operates in traditional mode without Synth predictions.
|
||||
/// The actual Synth configuration is managed centrally in SynthPredictionService.
|
||||
/// </summary>
|
||||
[Id(17)]
|
||||
public bool UseSynthApi { get; set; } = false;
|
||||
|
||||
/// <summary>
|
||||
/// Whether to use Synth predictions for position sizing adjustments and risk assessment
|
||||
/// </summary>
|
||||
[Id(18)]
|
||||
public bool UseForPositionSizing { get; set; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// Whether to use Synth predictions for signal filtering
|
||||
/// </summary>
|
||||
[Id(19)]
|
||||
public bool UseForSignalFiltering { get; set; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// Whether to use Synth predictions for dynamic stop-loss/take-profit adjustments
|
||||
/// </summary>
|
||||
[Id(20)]
|
||||
public bool UseForDynamicStopLoss { get; set; } = true;
|
||||
}
|
||||
@@ -1,20 +1,41 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using Managing.Common;
|
||||
using Orleans;
|
||||
using Skender.Stock.Indicators;
|
||||
|
||||
namespace Managing.Domain.Candles
|
||||
{
|
||||
[GenerateSerializer]
|
||||
public class Candle : IQuote
|
||||
{
|
||||
[Id(0)]
|
||||
[Required] public Enums.TradingExchanges Exchange { get; set; }
|
||||
|
||||
[Id(1)]
|
||||
[Required] public string Ticker { get; set; }
|
||||
|
||||
[Id(2)]
|
||||
[Required] public DateTime OpenTime { get; set; }
|
||||
|
||||
[Id(3)]
|
||||
[Required] public DateTime Date { get; set; }
|
||||
|
||||
[Id(4)]
|
||||
[Required] public decimal Open { get; set; }
|
||||
|
||||
[Id(5)]
|
||||
[Required] public decimal Close { get; set; }
|
||||
|
||||
[Id(6)]
|
||||
[Required] public decimal High { get; set; }
|
||||
|
||||
[Id(7)]
|
||||
[Required] public decimal Low { get; set; }
|
||||
|
||||
[Id(8)]
|
||||
[Required] public Enums.Timeframe Timeframe { get; set; }
|
||||
|
||||
[Id(9)]
|
||||
public decimal Volume { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -1,9 +1,19 @@
|
||||
namespace Managing.Domain.Evm;
|
||||
using Orleans;
|
||||
|
||||
namespace Managing.Domain.Evm;
|
||||
|
||||
[GenerateSerializer]
|
||||
public class Chain
|
||||
{
|
||||
[Id(0)]
|
||||
public string Id { get; set; }
|
||||
|
||||
[Id(1)]
|
||||
public string RpcUrl { get; set; }
|
||||
|
||||
[Id(2)]
|
||||
public string Name { get; set; }
|
||||
|
||||
[Id(3)]
|
||||
public int ChainId { get; set; }
|
||||
}
|
||||
@@ -8,6 +8,7 @@
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Exilion.TradingAtomics" Version="1.0.4"/>
|
||||
<PackageReference Include="Microsoft.Orleans.Core.Abstractions" Version="9.2.1" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.3"/>
|
||||
<PackageReference Include="Skender.Stock.Indicators" Version="2.5.0"/>
|
||||
</ItemGroup>
|
||||
|
||||
@@ -1,17 +1,28 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using Orleans;
|
||||
using static Managing.Common.Enums;
|
||||
|
||||
[GenerateSerializer]
|
||||
public class LightMoneyManagement
|
||||
{
|
||||
[Id(0)]
|
||||
[Required] public string Name { get; set; }
|
||||
|
||||
[Id(1)]
|
||||
[Required] public Timeframe Timeframe { get; set; }
|
||||
|
||||
[Id(2)]
|
||||
[Required] public decimal StopLoss { get; set; }
|
||||
|
||||
[Id(3)]
|
||||
[Required] public decimal TakeProfit { get; set; }
|
||||
|
||||
[Id(4)]
|
||||
[Required] public decimal Leverage { get; set; }
|
||||
|
||||
public void FormatPercentage()
|
||||
{
|
||||
StopLoss /= 100;
|
||||
TakeProfit /= 100;
|
||||
}
|
||||
public void FormatPercentage()
|
||||
{
|
||||
StopLoss /= 100;
|
||||
TakeProfit /= 100;
|
||||
}
|
||||
}
|
||||
@@ -1,9 +1,12 @@
|
||||
using Managing.Domain.Users;
|
||||
using Orleans;
|
||||
|
||||
namespace Managing.Domain.MoneyManagements
|
||||
{
|
||||
[GenerateSerializer]
|
||||
public class MoneyManagement : LightMoneyManagement
|
||||
{
|
||||
[Id(5)]
|
||||
public User User { get; set; }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using Managing.Common;
|
||||
using Orleans;
|
||||
|
||||
namespace Managing.Domain.Risk;
|
||||
|
||||
@@ -7,6 +8,7 @@ namespace Managing.Domain.Risk;
|
||||
/// Risk management configuration for trading bots
|
||||
/// Contains all configurable risk parameters for probabilistic analysis and position sizing
|
||||
/// </summary>
|
||||
[GenerateSerializer]
|
||||
public class RiskManagement
|
||||
{
|
||||
/// <summary>
|
||||
@@ -14,6 +16,7 @@ public class RiskManagement
|
||||
/// Signals with SL probability above this threshold may be filtered out
|
||||
/// Range: 0.05 (5%) to 0.50 (50%)
|
||||
/// </summary>
|
||||
[Id(0)]
|
||||
[Range(0.05, 0.50)]
|
||||
[Required]
|
||||
public decimal AdverseProbabilityThreshold { get; set; } = 0.20m;
|
||||
@@ -23,6 +26,7 @@ public class RiskManagement
|
||||
/// Used for additional signal filtering and confidence assessment
|
||||
/// Range: 0.10 (10%) to 0.70 (70%)
|
||||
/// </summary>
|
||||
[Id(1)]
|
||||
[Range(0.10, 0.70)]
|
||||
[Required]
|
||||
public decimal FavorableProbabilityThreshold { get; set; } = 0.30m;
|
||||
@@ -32,6 +36,7 @@ public class RiskManagement
|
||||
/// Higher values = more risk-averse behavior in utility calculations
|
||||
/// Range: 0.1 (risk-seeking) to 5.0 (highly risk-averse)
|
||||
/// </summary>
|
||||
[Id(2)]
|
||||
[Range(0.1, 5.0)]
|
||||
[Required]
|
||||
public decimal RiskAversion { get; set; } = 1.0m;
|
||||
@@ -41,6 +46,7 @@ public class RiskManagement
|
||||
/// Trades with Kelly fraction below this threshold are considered unfavorable
|
||||
/// Range: 0.5% to 10%
|
||||
/// </summary>
|
||||
[Id(3)]
|
||||
[Range(0.005, 0.10)]
|
||||
[Required]
|
||||
public decimal KellyMinimumThreshold { get; set; } = 0.01m;
|
||||
@@ -50,6 +56,7 @@ public class RiskManagement
|
||||
/// Prevents over-allocation even when Kelly suggests higher percentages
|
||||
/// Range: 5% to 50%
|
||||
/// </summary>
|
||||
[Id(4)]
|
||||
[Range(0.05, 0.50)]
|
||||
[Required]
|
||||
public decimal KellyMaximumCap { get; set; } = 0.25m;
|
||||
@@ -59,6 +66,7 @@ public class RiskManagement
|
||||
/// Positions with higher liquidation risk may be blocked or reduced
|
||||
/// Range: 5% to 30%
|
||||
/// </summary>
|
||||
[Id(5)]
|
||||
[Range(0.05, 0.30)]
|
||||
[Required]
|
||||
public decimal MaxLiquidationProbability { get; set; } = 0.10m;
|
||||
@@ -68,6 +76,7 @@ public class RiskManagement
|
||||
/// Longer horizons provide more stable predictions but less responsive signals
|
||||
/// Range: 1 hour to 168 hours (1 week)
|
||||
/// </summary>
|
||||
[Id(6)]
|
||||
[Range(1, 168)]
|
||||
[Required]
|
||||
public int SignalValidationTimeHorizonHours { get; set; } = 24;
|
||||
@@ -77,6 +86,7 @@ public class RiskManagement
|
||||
/// Shorter horizons for more frequent risk updates on open positions
|
||||
/// Range: 1 hour to 48 hours
|
||||
/// </summary>
|
||||
[Id(7)]
|
||||
[Range(1, 48)]
|
||||
[Required]
|
||||
public int PositionMonitoringTimeHorizonHours { get; set; } = 6;
|
||||
@@ -86,6 +96,7 @@ public class RiskManagement
|
||||
/// Positions exceeding this liquidation risk will trigger warnings
|
||||
/// Range: 10% to 40%
|
||||
/// </summary>
|
||||
[Id(8)]
|
||||
[Range(0.10, 0.40)]
|
||||
[Required]
|
||||
public decimal PositionWarningThreshold { get; set; } = 0.20m;
|
||||
@@ -95,6 +106,7 @@ public class RiskManagement
|
||||
/// Positions exceeding this liquidation risk will be automatically closed
|
||||
/// Range: 30% to 80%
|
||||
/// </summary>
|
||||
[Id(9)]
|
||||
[Range(0.30, 0.80)]
|
||||
[Required]
|
||||
public decimal PositionAutoCloseThreshold { get; set; } = 0.50m;
|
||||
@@ -104,6 +116,7 @@ public class RiskManagement
|
||||
/// Values less than 1.0 implement fractional Kelly (e.g., 0.5 = half-Kelly)
|
||||
/// Range: 0.1 to 1.0
|
||||
/// </summary>
|
||||
[Id(10)]
|
||||
[Range(0.1, 1.0)]
|
||||
[Required]
|
||||
public decimal KellyFractionalMultiplier { get; set; } = 1.0m;
|
||||
@@ -111,18 +124,21 @@ public class RiskManagement
|
||||
/// <summary>
|
||||
/// Risk tolerance level affecting overall risk calculations
|
||||
/// </summary>
|
||||
[Id(11)]
|
||||
[Required]
|
||||
public Enums.RiskToleranceLevel RiskTolerance { get; set; } = Enums.RiskToleranceLevel.Moderate;
|
||||
|
||||
/// <summary>
|
||||
/// Whether to use Expected Utility Theory for decision making
|
||||
/// </summary>
|
||||
[Id(12)]
|
||||
[Required]
|
||||
public bool UseExpectedUtility { get; set; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// Whether to use Kelly Criterion for position sizing recommendations
|
||||
/// </summary>
|
||||
[Id(13)]
|
||||
[Required]
|
||||
public bool UseKellyCriterion { get; set; } = true;
|
||||
|
||||
|
||||
57
src/Managing.Domain/Scenarios/LightScenario.cs
Normal file
57
src/Managing.Domain/Scenarios/LightScenario.cs
Normal file
@@ -0,0 +1,57 @@
|
||||
using Managing.Domain.Strategies;
|
||||
using Orleans;
|
||||
|
||||
namespace Managing.Domain.Scenarios;
|
||||
|
||||
/// <summary>
|
||||
/// Lightweight scenario class for Orleans serialization
|
||||
/// Contains only the essential properties needed for backtesting
|
||||
/// </summary>
|
||||
[GenerateSerializer]
|
||||
public class LightScenario
|
||||
{
|
||||
public LightScenario(string name, int? loopbackPeriod = 1)
|
||||
{
|
||||
Name = name;
|
||||
Indicators = new List<LightIndicator>();
|
||||
LoopbackPeriod = loopbackPeriod;
|
||||
}
|
||||
|
||||
[Id(0)] public string Name { get; set; }
|
||||
|
||||
[Id(1)] public List<LightIndicator> Indicators { get; set; }
|
||||
|
||||
[Id(2)] public int? LoopbackPeriod { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Converts a full Scenario to a LightScenario
|
||||
/// </summary>
|
||||
public static LightScenario FromScenario(Scenario scenario)
|
||||
{
|
||||
var lightScenario = new LightScenario(scenario.Name, scenario.LoopbackPeriod)
|
||||
{
|
||||
Indicators = scenario.Indicators?.Select(LightIndicator.FromIndicator).ToList() ??
|
||||
new List<LightIndicator>()
|
||||
};
|
||||
return lightScenario;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Converts a LightScenario back to a full Scenario
|
||||
/// </summary>
|
||||
public Scenario ToScenario()
|
||||
{
|
||||
var scenario = new Scenario(Name, LoopbackPeriod)
|
||||
{
|
||||
Indicators = Indicators?.Select(li => li.ToIndicator()).ToList() ?? new List<Indicator>()
|
||||
};
|
||||
return scenario;
|
||||
}
|
||||
|
||||
public void AddIndicator(LightIndicator indicator)
|
||||
{
|
||||
if (Indicators == null)
|
||||
Indicators = new List<LightIndicator>();
|
||||
Indicators.Add(indicator);
|
||||
}
|
||||
}
|
||||
@@ -1,8 +1,10 @@
|
||||
using Managing.Domain.Strategies;
|
||||
using Managing.Domain.Users;
|
||||
using Orleans;
|
||||
|
||||
namespace Managing.Domain.Scenarios
|
||||
{
|
||||
[GenerateSerializer]
|
||||
public class Scenario
|
||||
{
|
||||
public Scenario(string name, int? loopbackPeriod = 1)
|
||||
@@ -12,9 +14,16 @@ namespace Managing.Domain.Scenarios
|
||||
LoopbackPeriod = loopbackPeriod;
|
||||
}
|
||||
|
||||
[Id(0)]
|
||||
public string Name { get; set; }
|
||||
|
||||
[Id(1)]
|
||||
public List<Indicator> Indicators { get; set; }
|
||||
|
||||
[Id(2)]
|
||||
public int? LoopbackPeriod { get; set; }
|
||||
|
||||
[Id(3)]
|
||||
public User User { get; set; }
|
||||
|
||||
public void AddIndicator(Indicator indicator)
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
using System.Runtime.Serialization;
|
||||
using System.Text.Json.Serialization;
|
||||
using Managing.Core.FixedSizedQueue;
|
||||
using Managing.Core.FixedSizedQueue;
|
||||
using Managing.Domain.Candles;
|
||||
using Managing.Domain.Scenarios;
|
||||
using Managing.Domain.Strategies.Base;
|
||||
@@ -20,18 +18,31 @@ namespace Managing.Domain.Strategies
|
||||
}
|
||||
|
||||
public string Name { get; set; }
|
||||
[JsonIgnore] [IgnoreDataMember] public FixedSizeQueue<Candle> Candles { get; set; }
|
||||
|
||||
public FixedSizeQueue<Candle> Candles { get; set; }
|
||||
|
||||
public IndicatorType Type { get; set; }
|
||||
|
||||
public SignalType SignalType { get; set; }
|
||||
|
||||
public int MinimumHistory { get; set; }
|
||||
|
||||
public int? Period { get; set; }
|
||||
|
||||
public int? FastPeriods { get; set; }
|
||||
|
||||
public int? SlowPeriods { get; set; }
|
||||
|
||||
public int? SignalPeriods { get; set; }
|
||||
|
||||
public double? Multiplier { get; set; }
|
||||
|
||||
public int? SmoothPeriods { get; set; }
|
||||
|
||||
public int? StochPeriods { get; set; }
|
||||
|
||||
public int? CyclePeriods { get; set; }
|
||||
|
||||
public User User { get; set; }
|
||||
|
||||
public virtual List<LightSignal> Run()
|
||||
|
||||
84
src/Managing.Domain/Strategies/LightIndicator.cs
Normal file
84
src/Managing.Domain/Strategies/LightIndicator.cs
Normal file
@@ -0,0 +1,84 @@
|
||||
using Managing.Domain.Scenarios;
|
||||
using Orleans;
|
||||
using static Managing.Common.Enums;
|
||||
|
||||
namespace Managing.Domain.Strategies;
|
||||
|
||||
/// <summary>
|
||||
/// Lightweight indicator class for Orleans serialization
|
||||
/// Contains only the essential properties needed for backtesting
|
||||
/// </summary>
|
||||
[GenerateSerializer]
|
||||
public class LightIndicator
|
||||
{
|
||||
public LightIndicator(string name, IndicatorType type)
|
||||
{
|
||||
Name = name;
|
||||
Type = type;
|
||||
SignalType = ScenarioHelpers.GetSignalType(type);
|
||||
}
|
||||
|
||||
[Id(0)] public string Name { get; set; }
|
||||
|
||||
[Id(1)] public IndicatorType Type { get; set; }
|
||||
|
||||
[Id(2)] public SignalType SignalType { get; set; }
|
||||
|
||||
[Id(3)] public int MinimumHistory { get; set; }
|
||||
|
||||
[Id(4)] public int? Period { get; set; }
|
||||
|
||||
[Id(5)] public int? FastPeriods { get; set; }
|
||||
|
||||
[Id(6)] public int? SlowPeriods { get; set; }
|
||||
|
||||
[Id(7)] public int? SignalPeriods { get; set; }
|
||||
|
||||
[Id(8)] public double? Multiplier { get; set; }
|
||||
|
||||
[Id(9)] public int? SmoothPeriods { get; set; }
|
||||
|
||||
[Id(10)] public int? StochPeriods { get; set; }
|
||||
|
||||
[Id(11)] public int? CyclePeriods { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Converts a full Indicator to a LightIndicator
|
||||
/// </summary>
|
||||
public static LightIndicator FromIndicator(Indicator indicator)
|
||||
{
|
||||
return new LightIndicator(indicator.Name, indicator.Type)
|
||||
{
|
||||
SignalType = indicator.SignalType,
|
||||
MinimumHistory = indicator.MinimumHistory,
|
||||
Period = indicator.Period,
|
||||
FastPeriods = indicator.FastPeriods,
|
||||
SlowPeriods = indicator.SlowPeriods,
|
||||
SignalPeriods = indicator.SignalPeriods,
|
||||
Multiplier = indicator.Multiplier,
|
||||
SmoothPeriods = indicator.SmoothPeriods,
|
||||
StochPeriods = indicator.StochPeriods,
|
||||
CyclePeriods = indicator.CyclePeriods
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Converts a LightIndicator back to a full Indicator
|
||||
/// </summary>
|
||||
public Indicator ToIndicator()
|
||||
{
|
||||
return new Indicator(Name, Type)
|
||||
{
|
||||
SignalType = SignalType,
|
||||
MinimumHistory = MinimumHistory,
|
||||
Period = Period,
|
||||
FastPeriods = FastPeriods,
|
||||
SlowPeriods = SlowPeriods,
|
||||
SignalPeriods = SignalPeriods,
|
||||
Multiplier = Multiplier,
|
||||
SmoothPeriods = SmoothPeriods,
|
||||
StochPeriods = StochPeriods,
|
||||
CyclePeriods = CyclePeriods
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -2,8 +2,10 @@ using System.ComponentModel.DataAnnotations;
|
||||
using System.Globalization;
|
||||
using Managing.Core;
|
||||
using Managing.Domain.Candles;
|
||||
using Orleans;
|
||||
using static Managing.Common.Enums;
|
||||
|
||||
[GenerateSerializer]
|
||||
public class LightSignal : ValueObject
|
||||
{
|
||||
public LightSignal(Ticker ticker, TradeDirection direction, Confidence confidence, Candle candle, DateTime date,
|
||||
@@ -24,17 +26,40 @@ public class LightSignal : ValueObject
|
||||
$"{indicatorName}-{indicatorType}-{direction}-{ticker}-{candle?.Close.ToString(CultureInfo.InvariantCulture)}-{date:yyyyMMdd-HHmmss}";
|
||||
}
|
||||
|
||||
[Id(0)]
|
||||
[Required] public SignalStatus Status { get; set; }
|
||||
|
||||
[Id(1)]
|
||||
[Required] public TradeDirection Direction { get; }
|
||||
|
||||
[Id(2)]
|
||||
[Required] public Confidence Confidence { get; set; }
|
||||
|
||||
[Id(3)]
|
||||
[Required] public Timeframe Timeframe { get; }
|
||||
|
||||
[Id(4)]
|
||||
[Required] public DateTime Date { get; private set; }
|
||||
|
||||
[Id(5)]
|
||||
[Required] public Candle Candle { get; }
|
||||
|
||||
[Id(6)]
|
||||
[Required] public string Identifier { get; }
|
||||
|
||||
[Id(7)]
|
||||
[Required] public Ticker Ticker { get; }
|
||||
|
||||
[Id(8)]
|
||||
[Required] public TradingExchanges Exchange { get; set; }
|
||||
|
||||
[Id(9)]
|
||||
[Required] public IndicatorType IndicatorType { get; set; }
|
||||
|
||||
[Id(10)]
|
||||
[Required] public SignalType SignalType { get; set; }
|
||||
|
||||
[Id(11)]
|
||||
[Required] public string IndicatorName { get; set; }
|
||||
|
||||
protected override IEnumerable<object> GetEqualityComponents()
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.Text.Json.Serialization;
|
||||
using Managing.Domain.Users;
|
||||
using Orleans;
|
||||
using static Managing.Common.Enums;
|
||||
|
||||
namespace Managing.Domain.Trades
|
||||
{
|
||||
[GenerateSerializer]
|
||||
public class Position
|
||||
{
|
||||
public Position(string identifier, string accountName, TradeDirection originDirection, Ticker ticker,
|
||||
@@ -21,28 +23,53 @@ namespace Managing.Domain.Trades
|
||||
User = user;
|
||||
}
|
||||
|
||||
[Id(0)]
|
||||
[Required] public string AccountName { get; set; }
|
||||
|
||||
[Id(1)]
|
||||
[Required] public DateTime Date { get; set; }
|
||||
|
||||
[Id(2)]
|
||||
[Required] public TradeDirection OriginDirection { get; set; }
|
||||
|
||||
[Id(3)]
|
||||
[Required] public Ticker Ticker { get; set; }
|
||||
|
||||
[Id(4)]
|
||||
[Required] public LightMoneyManagement MoneyManagement { get; set; }
|
||||
|
||||
[Id(5)]
|
||||
[Required] [JsonPropertyName("Open")] public Trade Open { get; set; }
|
||||
|
||||
[Id(6)]
|
||||
[Required]
|
||||
[JsonPropertyName("StopLoss")]
|
||||
public Trade StopLoss { get; set; }
|
||||
|
||||
[Id(7)]
|
||||
[Required]
|
||||
[JsonPropertyName("TakeProfit1")]
|
||||
public Trade TakeProfit1 { get; set; }
|
||||
|
||||
[Id(8)]
|
||||
[JsonPropertyName("TakeProfit2")] public Trade TakeProfit2 { get; set; }
|
||||
|
||||
[Id(9)]
|
||||
[JsonPropertyName("ProfitAndLoss")] public ProfitAndLoss ProfitAndLoss { get; set; }
|
||||
|
||||
[Id(10)]
|
||||
[Required] public PositionStatus Status { get; set; }
|
||||
|
||||
[Id(11)]
|
||||
public string SignalIdentifier { get; set; }
|
||||
|
||||
[Id(12)]
|
||||
[Required] public string Identifier { get; set; }
|
||||
|
||||
[Id(13)]
|
||||
[Required] public PositionInitiator Initiator { get; set; }
|
||||
|
||||
[Id(14)]
|
||||
[Required] public User User { get; set; }
|
||||
|
||||
public bool IsFinished()
|
||||
|
||||
@@ -1,13 +1,18 @@
|
||||
using static Managing.Common.Enums;
|
||||
using Orleans;
|
||||
using static Managing.Common.Enums;
|
||||
|
||||
namespace Managing.Domain.Trades
|
||||
{
|
||||
[GenerateSerializer]
|
||||
public sealed class ProfitAndLoss
|
||||
{
|
||||
[Id(0)]
|
||||
public decimal Realized { get; set; }
|
||||
|
||||
[Id(1)]
|
||||
public decimal Net { get; set; }
|
||||
|
||||
[Id(2)]
|
||||
public decimal AverageOpenPrice { get; private set; }
|
||||
private const decimal _multiplier = 100000;
|
||||
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using Orleans;
|
||||
using static Managing.Common.Enums;
|
||||
|
||||
namespace Managing.Domain.Trades
|
||||
{
|
||||
[GenerateSerializer]
|
||||
public class Trade
|
||||
{
|
||||
public Trade(DateTime date, TradeDirection direction, TradeStatus status, TradeType tradeType, Ticker ticker,
|
||||
@@ -21,16 +23,37 @@ namespace Managing.Domain.Trades
|
||||
Fee = 0;
|
||||
}
|
||||
|
||||
[Id(0)]
|
||||
[Required] public decimal Fee { get; set; }
|
||||
|
||||
[Id(1)]
|
||||
[Required] public DateTime Date { get; set; }
|
||||
|
||||
[Id(2)]
|
||||
[Required] public TradeDirection Direction { get; set; }
|
||||
|
||||
[Id(3)]
|
||||
[Required] public TradeStatus Status { get; set; }
|
||||
|
||||
[Id(4)]
|
||||
[Required] public TradeType TradeType { get; set; }
|
||||
|
||||
[Id(5)]
|
||||
[Required] public Ticker Ticker { get; set; }
|
||||
|
||||
[Id(6)]
|
||||
[Required] public decimal Quantity { get; set; }
|
||||
|
||||
[Id(7)]
|
||||
[Required] public decimal Price { get; set; }
|
||||
|
||||
[Id(8)]
|
||||
[Required] public decimal Leverage { get; set; }
|
||||
|
||||
[Id(9)]
|
||||
[Required] public string ExchangeOrderId { get; set; }
|
||||
|
||||
[Id(10)]
|
||||
[Required] public string Message { get; set; }
|
||||
|
||||
public void SetStatus(TradeStatus status)
|
||||
|
||||
@@ -1,12 +1,23 @@
|
||||
using Managing.Domain.Accounts;
|
||||
using Orleans;
|
||||
|
||||
namespace Managing.Domain.Users;
|
||||
|
||||
[GenerateSerializer]
|
||||
public class User
|
||||
{
|
||||
[Id(0)]
|
||||
public string Name { get; set; }
|
||||
|
||||
[Id(1)]
|
||||
public List<Account> Accounts { get; set; }
|
||||
|
||||
[Id(2)]
|
||||
public string AgentName { get; set; }
|
||||
|
||||
[Id(3)]
|
||||
public string AvatarUrl { get; set; }
|
||||
|
||||
[Id(4)]
|
||||
public string TelegramChannel { get; set; }
|
||||
}
|
||||
Reference in New Issue
Block a user