diff --git a/csharp/TraderBot/KellyCriterion.cs b/csharp/TraderBot/KellyCriterion.cs
new file mode 100644
index 00000000..50030a28
--- /dev/null
+++ b/csharp/TraderBot/KellyCriterion.cs
@@ -0,0 +1,79 @@
+namespace TraderBot;
+
+public static class KellyCriterion
+{
+ ///
+ /// Calculates the optimal bet size fraction using the Kelly Criterion formula.
+ /// Formula: f = (bp - q) / b
+ /// Where:
+ /// - f = fraction of capital to bet
+ /// - b = profit/loss ratio (odds)
+ /// - p = probability of winning
+ /// - q = probability of losing (1-p)
+ ///
+ /// Probability of winning (0.0 to 1.0)
+ /// The ratio of profit to loss (e.g., 2.0 means profit is 2x the loss)
+ /// Maximum fraction to limit risk (default 0.25)
+ /// The optimal fraction of capital to bet (0.0 to maxFraction)
+ public static double CalculateOptimalBetSize(double winProbability, double profitLossRatio, double maxFraction = 0.25)
+ {
+ if (winProbability < 0 || winProbability > 1)
+ throw new ArgumentException("Win probability must be between 0 and 1", nameof(winProbability));
+
+ if (profitLossRatio <= 0)
+ throw new ArgumentException("Profit/loss ratio must be positive", nameof(profitLossRatio));
+
+ if (maxFraction <= 0 || maxFraction > 1)
+ throw new ArgumentException("Max fraction must be between 0 and 1", nameof(maxFraction));
+
+ double lossProbability = 1.0 - winProbability;
+
+ // Kelly Criterion formula: f = (bp - q) / b
+ double kellyFraction = (profitLossRatio * winProbability - lossProbability) / profitLossRatio;
+
+ // Return 0 if Kelly suggests negative betting (negative expected value)
+ if (kellyFraction <= 0)
+ return 0.0;
+
+ // Cap at maximum fraction to limit risk
+ return Math.Min(kellyFraction, maxFraction);
+ }
+
+ ///
+ /// Calculates the win probability and profit/loss ratio from historical operations
+ ///
+ /// List of completed operations
+ /// Tuple containing (winProbability, profitLossRatio)
+ public static (double WinProbability, double ProfitLossRatio) CalculateHistoricalMetrics(
+ IEnumerable<(DateTime Date, decimal BuyPrice, decimal SellPrice)> operations)
+ {
+ var operationsList = operations.ToList();
+ if (operationsList.Count < 10) // Need minimum historical data
+ return (0.5, 1.0); // Default conservative values
+
+ var wins = 0;
+ var totalProfit = 0.0m;
+ var totalLoss = 0.0m;
+
+ foreach (var op in operationsList)
+ {
+ var profit = op.SellPrice - op.BuyPrice;
+ if (profit > 0)
+ {
+ wins++;
+ totalProfit += profit;
+ }
+ else if (profit < 0)
+ {
+ totalLoss += Math.Abs(profit);
+ }
+ }
+
+ var winProbability = (double)wins / operationsList.Count;
+ var avgProfit = wins > 0 ? (double)(totalProfit / wins) : 0.0;
+ var avgLoss = (operationsList.Count - wins) > 0 ? (double)(totalLoss / (operationsList.Count - wins)) : 1.0;
+ var profitLossRatio = avgLoss > 0 ? avgProfit / avgLoss : 1.0;
+
+ return (winProbability, Math.Max(profitLossRatio, 0.1)); // Minimum ratio to avoid division issues
+ }
+}
\ No newline at end of file
diff --git a/csharp/TraderBot/TradingService.cs b/csharp/TraderBot/TradingService.cs
index 0302809b..013b238a 100644
--- a/csharp/TraderBot/TradingService.cs
+++ b/csharp/TraderBot/TradingService.cs
@@ -39,6 +39,7 @@ public class TradingService : BackgroundService
protected readonly ConcurrentDictionary ActiveSellOrders;
protected readonly ConcurrentDictionary LotsSets;
protected readonly ConcurrentDictionary ActiveSellOrderSourcePrice;
+ protected readonly List<(DateTime Date, decimal BuyPrice, decimal SellPrice)> CompletedOperations;
public TradingService(ILogger logger, InvestApiClient investApi, IHostApplicationLifetime lifetime, TradingSettings settings)
{
@@ -111,6 +112,7 @@ public TradingService(ILogger logger, InvestApiClient investApi,
ActiveSellOrders = new ConcurrentDictionary();
LotsSets = new ConcurrentDictionary();
ActiveSellOrderSourcePrice = new ConcurrentDictionary();
+ CompletedOperations = new List<(DateTime, decimal, decimal)>();
LastOperationsCheckpoint = settings.LoadOperationsFrom;
}
@@ -290,7 +292,15 @@ protected void TrySubtractTradesFromOrder(ConcurrentDictionary o.Price == bestBid)?.Quantity ?? 0;
Logger.LogInformation($"marketLotsAtTargetPrice: {marketLotsAtTargetPrice}");
var response = await PlaceBuyOrder(lots, bestBid);
@@ -544,7 +554,7 @@ await marketDataStream.RequestStream.WriteAsync(new MarketDataRequest
var lotPrice = bestBid * LotSize;
if (cashBalance > lotPrice)
{
- var lots = (long)(cashBalance / lotPrice);
+ var lots = CalculateOptimalLotSize(cashBalance, lotPrice);
var marketLotsAtTargetPrice = orderBook.Bids.FirstOrDefault(o => o.Price == bestBid)?.Quantity ?? 0;
Logger.LogInformation($"marketLotsAtTargetPrice: {marketLotsAtTargetPrice}");
var response = await PlaceBuyOrder(lots, bestBid);
@@ -652,6 +662,57 @@ private bool IsTimeToBuy()
{
var currentTime = DateTime.UtcNow.TimeOfDay;
return currentTime > MinimumTimeToBuy && currentTime < MaximumTimeToBuy;
+ }
+
+ private long CalculateOptimalLotSize(decimal cashBalance, decimal lotPrice)
+ {
+ if (!Settings.UseKellyCriterion)
+ {
+ // Use traditional sizing: all available cash
+ return (long)(cashBalance / lotPrice);
+ }
+
+ double winProbability = Settings.WinProbability;
+ double profitLossRatio = Settings.ProfitLossRatio;
+
+ // If we have enough historical data, calculate metrics dynamically
+ if (CompletedOperations.Count >= 10)
+ {
+ var (historicalWinProb, historicalRatio) = KellyCriterion.CalculateHistoricalMetrics(CompletedOperations);
+ winProbability = historicalWinProb;
+ profitLossRatio = historicalRatio;
+ Logger.LogInformation($"Using historical metrics - Win Probability: {winProbability:F3}, Profit/Loss Ratio: {profitLossRatio:F3}");
+ }
+ else
+ {
+ Logger.LogInformation($"Using configured metrics - Win Probability: {winProbability:F3}, Profit/Loss Ratio: {profitLossRatio:F3}");
+ }
+
+ var kellyFraction = KellyCriterion.CalculateOptimalBetSize(winProbability, profitLossRatio, Settings.KellyFractionLimit);
+ var optimalCashToUse = cashBalance * (decimal)kellyFraction;
+ var lots = (long)Math.Max(1, optimalCashToUse / lotPrice); // Ensure at least 1 lot
+
+ Logger.LogInformation($"Kelly Criterion: Fraction={kellyFraction:F3}, OptimalCash={optimalCashToUse:F2}, Lots={lots}");
+
+ return lots;
+ }
+
+ private void TrackCompletedOperation(decimal buyPrice, decimal sellPrice)
+ {
+ lock (CompletedOperations)
+ {
+ CompletedOperations.Add((DateTime.UtcNow, buyPrice, sellPrice));
+
+ // Keep only last 100 operations to prevent memory growth
+ if (CompletedOperations.Count > 100)
+ {
+ CompletedOperations.RemoveAt(0);
+ }
+ }
+
+ var profit = sellPrice - buyPrice;
+ var profitPercent = (profit / buyPrice) * 100;
+ Logger.LogInformation($"Operation completed: Buy={buyPrice}, Sell={sellPrice}, Profit={profit:F4} ({profitPercent:F2}%)");
}
private async Task<(decimal, decimal)> GetCashBalance(bool forceRemote = false)
diff --git a/csharp/TraderBot/TradingSettings.cs b/csharp/TraderBot/TradingSettings.cs
index 884a25df..5f3404a8 100644
--- a/csharp/TraderBot/TradingSettings.cs
+++ b/csharp/TraderBot/TradingSettings.cs
@@ -17,4 +17,8 @@ public class TradingSettings
public long EarlySellOwnedLotsDelta { get; set; }
public decimal EarlySellOwnedLotsMultiplier { get; set; }
public DateTime LoadOperationsFrom { get; set; }
+ public bool UseKellyCriterion { get; set; }
+ public double WinProbability { get; set; }
+ public double ProfitLossRatio { get; set; }
+ public double KellyFractionLimit { get; set; } = 0.25;
}
\ No newline at end of file
diff --git a/csharp/TraderBot/appsettings.TMON.json b/csharp/TraderBot/appsettings.TMON.json
index c7b66d7a..6d583a41 100644
--- a/csharp/TraderBot/appsettings.TMON.json
+++ b/csharp/TraderBot/appsettings.TMON.json
@@ -24,6 +24,10 @@
"MaximumTimeToBuy": "23:59:59",
"EarlySellOwnedLotsDelta": 300000,
"EarlySellOwnedLotsMultiplier": 0,
- "LoadOperationsFrom": "2025-03-01T00:00:01.3389860Z"
+ "LoadOperationsFrom": "2025-03-01T00:00:01.3389860Z",
+ "UseKellyCriterion": true,
+ "WinProbability": 0.55,
+ "ProfitLossRatio": 1.2,
+ "KellyFractionLimit": 0.25
}
}
diff --git a/csharp/TraderBot/appsettings.TRUR.json b/csharp/TraderBot/appsettings.TRUR.json
index 1dc848e6..e873e199 100644
--- a/csharp/TraderBot/appsettings.TRUR.json
+++ b/csharp/TraderBot/appsettings.TRUR.json
@@ -24,6 +24,10 @@
"MaximumTimeToBuy": "14:45:00",
"EarlySellOwnedLotsDelta": 300000,
"EarlySellOwnedLotsMultiplier": 0,
- "LoadOperationsFrom": "2025-03-01T00:00:01.3389860Z"
+ "LoadOperationsFrom": "2025-03-01T00:00:01.3389860Z",
+ "UseKellyCriterion": true,
+ "WinProbability": 0.52,
+ "ProfitLossRatio": 1.1,
+ "KellyFractionLimit": 0.2
}
}
diff --git a/examples/KELLY_CRITERION_README.md b/examples/KELLY_CRITERION_README.md
new file mode 100644
index 00000000..ec9067e0
--- /dev/null
+++ b/examples/KELLY_CRITERION_README.md
@@ -0,0 +1,182 @@
+# Kelly Criterion Implementation for TraderBot
+
+## Overview
+
+This implementation adds Kelly Criterion position sizing to the TraderBot, enabling optimal capital allocation to maximize long-term profit while managing risk. The Kelly Criterion was developed by John Kelly at Bell Labs in 1956 and is widely used by professional traders and investors.
+
+## Mathematical Formula
+
+The Kelly Criterion calculates the optimal fraction of capital to risk using:
+
+```
+f = (bp - q) / b
+```
+
+Where:
+- `f` = fraction of capital to bet/invest
+- `b` = profit/loss ratio (odds received)
+- `p` = probability of winning
+- `q` = probability of losing (1-p)
+
+## Key Features
+
+### 1. Optimal Position Sizing
+- Calculates optimal lot size based on historical performance or configured parameters
+- Prevents over-betting and under-betting
+- Maximizes long-term geometric growth rate
+
+### 2. Dynamic Learning
+- Automatically calculates win probability and profit/loss ratio from completed trades
+- Adapts position sizing based on actual performance
+- Falls back to configured values when insufficient historical data
+
+### 3. Risk Management
+- Configurable maximum fraction limit (default 25%) to prevent excessive risk
+- Returns 0% allocation for negative expected value strategies
+- Built-in safeguards against calculation errors
+
+### 4. Comprehensive Configuration
+- Toggle Kelly Criterion on/off per trading instrument
+- Configure initial win probability and profit/loss ratio estimates
+- Set maximum risk fraction limits
+
+## Configuration Parameters
+
+Add these parameters to your `appsettings.json` under `TradingSettings`:
+
+```json
+{
+ "TradingSettings": {
+ // ... existing settings ...
+ "UseKellyCriterion": true,
+ "WinProbability": 0.55,
+ "ProfitLossRatio": 1.2,
+ "KellyFractionLimit": 0.25
+ }
+}
+```
+
+### Parameter Details
+
+- **UseKellyCriterion**: Enable/disable Kelly position sizing (default: false)
+- **WinProbability**: Initial estimate of win rate (0.0 to 1.0)
+- **ProfitLossRatio**: Initial estimate of average profit to average loss ratio
+- **KellyFractionLimit**: Maximum fraction of capital to risk (0.0 to 1.0, default: 0.25)
+
+## Real-World Examples
+
+### Conservative Trading (Example 1)
+- Win Rate: 52%
+- Profit/Loss Ratio: 1.1:1
+- Max Risk: 10%
+- **Result: 8.4% of capital per trade**
+
+### Aggressive Trading (Example 2)
+- Win Rate: 65%
+- Profit/Loss Ratio: 1.5:1
+- Max Risk: 50%
+- **Result: 41.7% of capital per trade**
+
+### High Win Rate, Low Profit (Example 3)
+- Win Rate: 80%
+- Profit/Loss Ratio: 0.8:1
+- Max Risk: 25%
+- **Result: 25.0% of capital per trade (capped)**
+
+### Breakeven Strategy (Example 4)
+- Win Rate: 50%
+- Profit/Loss Ratio: 1.0:1
+- Max Risk: 25%
+- **Result: 0.0% of capital per trade (negative expected value)**
+
+## Implementation Details
+
+### Core Components
+
+1. **KellyCriterion.cs**: Static calculation methods
+2. **TradingSettings.cs**: Configuration parameters
+3. **TradingService.cs**: Integration with existing trading logic
+
+### Key Methods
+
+- `CalculateOptimalBetSize()`: Main Kelly calculation
+- `CalculateHistoricalMetrics()`: Dynamic learning from trade history
+- `CalculateOptimalLotSize()`: Integration with existing lot sizing
+- `TrackCompletedOperation()`: Trade history tracking
+
+### Behavior Changes
+
+When Kelly Criterion is enabled:
+1. **Position Sizing**: Uses Kelly formula instead of "all available cash"
+2. **Risk Management**: Automatically reduces position size for poor-performing strategies
+3. **Learning**: Adapts to actual performance over time
+4. **Logging**: Provides detailed Kelly calculation information
+
+When Kelly Criterion is disabled:
+- Falls back to original position sizing logic
+- No behavior changes to existing functionality
+
+## Testing
+
+Comprehensive test suite includes:
+- Mathematical accuracy tests
+- Edge case handling
+- Historical metrics calculation
+- Real-world scenario simulations
+
+Run tests with:
+```bash
+cd examples
+dotnet run
+```
+
+## Risk Considerations
+
+### Important Warnings
+
+1. **Accurate Probabilities Required**: Kelly Criterion requires accurate estimates of win probability and profit/loss ratios. Overestimating leads to excessive risk.
+
+2. **Volatility**: Kelly sizing can be volatile. Consider using fractional Kelly (e.g., 50% of calculated size) for smoother equity curves.
+
+3. **Historical Data**: Algorithm needs minimum 10 completed trades for dynamic learning. Uses configured values otherwise.
+
+4. **Market Conditions**: Kelly assumes consistent market conditions. Performance may vary during regime changes.
+
+### Best Practices
+
+- Start with conservative estimates (lower win rates, profit/loss ratios)
+- Use fractional Kelly (25% or less) to reduce volatility
+- Monitor performance and adjust parameters based on actual results
+- Maintain diverse trading strategies to spread risk
+
+## Advanced Usage
+
+### Fractional Kelly
+
+Many professional traders use fractional Kelly to reduce volatility:
+- Full Kelly: Use calculated fraction
+- Half Kelly: Use 50% of calculated fraction
+- Quarter Kelly: Use 25% of calculated fraction
+
+Set `KellyFractionLimit` to implement fractional Kelly.
+
+### Dynamic Adjustment
+
+The system automatically switches to historical metrics after 10+ completed trades:
+- Improves accuracy over time
+- Adapts to changing market conditions
+- Provides more reliable position sizing
+
+## References
+
+- Kelly, J. L. (1956). "A New Interpretation of Information Rate"
+- Thorp, E. O. (2006). "The Kelly Capital Growth Investment Criterion"
+- MacLean, L. C., Thorp, E. O., & Ziemba, W. T. (2011). "The Kelly Capital Growth Investment Criterion: Theory and Practice"
+
+## Support
+
+For questions or issues related to Kelly Criterion implementation:
+1. Review configuration parameters
+2. Check log output for Kelly calculation details
+3. Run test suite to verify functionality
+4. Ensure minimum trade history for dynamic learning
\ No newline at end of file
diff --git a/examples/KellyCriterionTests.cs b/examples/KellyCriterionTests.cs
new file mode 100644
index 00000000..fea8ef8e
--- /dev/null
+++ b/examples/KellyCriterionTests.cs
@@ -0,0 +1,141 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using TraderBot;
+
+namespace TraderBot.Examples
+{
+ public class KellyCriterionTests
+ {
+ public static void RunAllTests()
+ {
+ Console.WriteLine("=== Kelly Criterion Tests ===");
+
+ TestBasicKellyCalculation();
+ TestNegativeExpectedValue();
+ TestMaximumFractionLimit();
+ TestEdgeCases();
+ TestHistoricalMetrics();
+
+ Console.WriteLine("=== All tests completed ===");
+ }
+
+ private static void TestBasicKellyCalculation()
+ {
+ Console.WriteLine("\n--- Test: Basic Kelly Calculation ---");
+
+ // Test case: 60% win rate, 2:1 profit/loss ratio
+ var winProbability = 0.6;
+ var profitLossRatio = 2.0;
+ var result = KellyCriterion.CalculateOptimalBetSize(winProbability, profitLossRatio, 1.0);
+
+ // Expected: (2 * 0.6 - 0.4) / 2 = 0.4
+ var expected = 0.4;
+ Console.WriteLine($"Win Rate: {winProbability}, P/L Ratio: {profitLossRatio}");
+ Console.WriteLine($"Expected: {expected:F3}, Actual: {result:F3}");
+
+ if (Math.Abs(result - expected) < 0.001)
+ Console.WriteLine("✓ PASS");
+ else
+ Console.WriteLine("✗ FAIL");
+ }
+
+ private static void TestNegativeExpectedValue()
+ {
+ Console.WriteLine("\n--- Test: Negative Expected Value ---");
+
+ // Test case: 40% win rate, 1:1 profit/loss ratio (negative expected value)
+ var winProbability = 0.4;
+ var profitLossRatio = 1.0;
+ var result = KellyCriterion.CalculateOptimalBetSize(winProbability, profitLossRatio);
+
+ Console.WriteLine($"Win Rate: {winProbability}, P/L Ratio: {profitLossRatio}");
+ Console.WriteLine($"Result: {result:F3}");
+
+ if (result == 0.0)
+ Console.WriteLine("✓ PASS - Correctly returns 0 for negative expected value");
+ else
+ Console.WriteLine("✗ FAIL - Should return 0 for negative expected value");
+ }
+
+ private static void TestMaximumFractionLimit()
+ {
+ Console.WriteLine("\n--- Test: Maximum Fraction Limit ---");
+
+ // Test case: Very high Kelly fraction that should be capped
+ var winProbability = 0.9;
+ var profitLossRatio = 10.0;
+ var maxFraction = 0.25;
+ var result = KellyCriterion.CalculateOptimalBetSize(winProbability, profitLossRatio, maxFraction);
+
+ Console.WriteLine($"Win Rate: {winProbability}, P/L Ratio: {profitLossRatio}, Max: {maxFraction}");
+ Console.WriteLine($"Result: {result:F3}");
+
+ if (result <= maxFraction)
+ Console.WriteLine("✓ PASS - Correctly capped at maximum fraction");
+ else
+ Console.WriteLine("✗ FAIL - Should be capped at maximum fraction");
+ }
+
+ private static void TestEdgeCases()
+ {
+ Console.WriteLine("\n--- Test: Edge Cases ---");
+
+ try
+ {
+ // Test invalid win probability
+ KellyCriterion.CalculateOptimalBetSize(-0.1, 1.0);
+ Console.WriteLine("✗ FAIL - Should throw exception for negative win probability");
+ }
+ catch (ArgumentException)
+ {
+ Console.WriteLine("✓ PASS - Correctly throws exception for negative win probability");
+ }
+
+ try
+ {
+ // Test invalid profit/loss ratio
+ KellyCriterion.CalculateOptimalBetSize(0.5, -1.0);
+ Console.WriteLine("✗ FAIL - Should throw exception for negative profit/loss ratio");
+ }
+ catch (ArgumentException)
+ {
+ Console.WriteLine("✓ PASS - Correctly throws exception for negative profit/loss ratio");
+ }
+ }
+
+ private static void TestHistoricalMetrics()
+ {
+ Console.WriteLine("\n--- Test: Historical Metrics Calculation ---");
+
+ var operations = new List<(DateTime, decimal, decimal)>
+ {
+ (DateTime.Now.AddDays(-10), 100m, 110m), // Win: +10
+ (DateTime.Now.AddDays(-9), 100m, 95m), // Loss: -5
+ (DateTime.Now.AddDays(-8), 100m, 108m), // Win: +8
+ (DateTime.Now.AddDays(-7), 100m, 92m), // Loss: -8
+ (DateTime.Now.AddDays(-6), 100m, 105m), // Win: +5
+ (DateTime.Now.AddDays(-5), 100m, 98m), // Loss: -2
+ (DateTime.Now.AddDays(-4), 100m, 112m), // Win: +12
+ (DateTime.Now.AddDays(-3), 100m, 97m), // Loss: -3
+ (DateTime.Now.AddDays(-2), 100m, 106m), // Win: +6
+ (DateTime.Now.AddDays(-1), 100m, 104m), // Win: +4
+ };
+
+ var (winProb, profitLossRatio) = KellyCriterion.CalculateHistoricalMetrics(operations);
+
+ // Expected: 6 wins out of 10 = 60% win rate
+ // Average win: (10+8+5+12+6+4)/6 = 7.5
+ // Average loss: (5+8+2+3)/4 = 4.5
+ // Profit/Loss ratio: 7.5/4.5 = 1.67
+
+ Console.WriteLine($"Win Probability: {winProb:F3} (expected ~0.600)");
+ Console.WriteLine($"Profit/Loss Ratio: {profitLossRatio:F3} (expected ~1.667)");
+
+ if (Math.Abs(winProb - 0.6) < 0.001 && Math.Abs(profitLossRatio - 1.667) < 0.01)
+ Console.WriteLine("✓ PASS - Historical metrics calculated correctly");
+ else
+ Console.WriteLine("✗ FAIL - Historical metrics calculation error");
+ }
+ }
+}
\ No newline at end of file
diff --git a/examples/KellyTestProject.csproj b/examples/KellyTestProject.csproj
new file mode 100644
index 00000000..706bad2a
--- /dev/null
+++ b/examples/KellyTestProject.csproj
@@ -0,0 +1,14 @@
+
+
+
+ Exe
+ net8
+ enable
+ enable
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/examples/KellyTestRunner.cs b/examples/KellyTestRunner.cs
new file mode 100644
index 00000000..561a08bd
--- /dev/null
+++ b/examples/KellyTestRunner.cs
@@ -0,0 +1,48 @@
+using System;
+using TraderBot.Examples;
+
+namespace TraderBot.Examples
+{
+ class Program
+ {
+ static void Main(string[] args)
+ {
+ Console.WriteLine("Kelly Criterion Test Suite");
+ Console.WriteLine("==========================");
+
+ try
+ {
+ KellyCriterionTests.RunAllTests();
+
+ Console.WriteLine("\n=== Real-world Examples ===");
+ DemonstrateRealWorldScenarios();
+ }
+ catch (Exception ex)
+ {
+ Console.WriteLine($"Test execution failed: {ex.Message}");
+ Console.WriteLine($"Stack trace: {ex.StackTrace}");
+ }
+
+ Console.WriteLine("\n=== Tests completed ===");
+ }
+
+ private static void DemonstrateRealWorldScenarios()
+ {
+ Console.WriteLine("\n--- Scenario 1: Conservative Trading ---");
+ var result1 = KellyCriterion.CalculateOptimalBetSize(0.52, 1.1, 0.1);
+ Console.WriteLine($"52% win rate, 1.1:1 ratio, max 10%: {result1:P1} of capital");
+
+ Console.WriteLine("\n--- Scenario 2: Aggressive Trading ---");
+ var result2 = KellyCriterion.CalculateOptimalBetSize(0.65, 1.5, 0.5);
+ Console.WriteLine($"65% win rate, 1.5:1 ratio, max 50%: {result2:P1} of capital");
+
+ Console.WriteLine("\n--- Scenario 3: High Win Rate, Low Profit ---");
+ var result3 = KellyCriterion.CalculateOptimalBetSize(0.8, 0.8, 0.25);
+ Console.WriteLine($"80% win rate, 0.8:1 ratio, max 25%: {result3:P1} of capital");
+
+ Console.WriteLine("\n--- Scenario 4: Breakeven Strategy ---");
+ var result4 = KellyCriterion.CalculateOptimalBetSize(0.5, 1.0, 0.25);
+ Console.WriteLine($"50% win rate, 1.0:1 ratio, max 25%: {result4:P1} of capital");
+ }
+ }
+}
\ No newline at end of file