Optimize strategies (#23)
* Update Tradingbox + set limit price * Change discord message
This commit is contained in:
177
docs/StrategyCombo-README.md
Normal file
177
docs/StrategyCombo-README.md
Normal file
@@ -0,0 +1,177 @@
|
|||||||
|
# Strategy Combination System
|
||||||
|
|
||||||
|
## Overview
|
||||||
|
|
||||||
|
The improved `TradingBox` strategy combination system provides sophisticated logic for combining multiple trading strategies with different purposes and behaviors. The system is designed around three distinct strategy types, each serving a specific role in the trading decision process.
|
||||||
|
|
||||||
|
## Strategy Types
|
||||||
|
|
||||||
|
### 1. Signal Strategies (`SignalType.Signal`)
|
||||||
|
- **Purpose**: Generate rare, precise entry signals when specific conditions are met
|
||||||
|
- **Behavior**: Sparse signal generation - only fire when opportunity is detected
|
||||||
|
- **Examples**: RSI Divergence, MACD Cross, Chandelier Exit
|
||||||
|
- **Weight**: High priority in final decision
|
||||||
|
|
||||||
|
### 2. Trend Strategies (`SignalType.Trend`)
|
||||||
|
- **Purpose**: Identify overall market direction on every candlestick
|
||||||
|
- **Behavior**: Continuous output (Long/Short/Neutral for each candle)
|
||||||
|
- **Examples**: EMA Trend, SuperTrend, Moving Average Cross
|
||||||
|
- **Weight**: Supporting role, validates signal direction
|
||||||
|
|
||||||
|
### 3. Context Strategies (`SignalType.Context`)
|
||||||
|
- **Purpose**: Provide market context to prevent trades in unfavorable conditions
|
||||||
|
- **Behavior**: Act as filters/guards (allow/block trades)
|
||||||
|
- **Examples**: Volatility filters, Volume filters, Time-based restrictions
|
||||||
|
- **Weight**: Veto power - can block otherwise valid signals
|
||||||
|
|
||||||
|
## Combination Logic
|
||||||
|
|
||||||
|
### Basic Flow
|
||||||
|
1. **Context Validation**: All context strategies must allow the trade (configurable)
|
||||||
|
2. **Signal Analysis**: Evaluate entry signals using majority voting
|
||||||
|
3. **Trend Analysis**: Determine overall market direction
|
||||||
|
4. **Final Decision**: Combine signal and trend with confidence scoring
|
||||||
|
|
||||||
|
### Decision Matrix
|
||||||
|
|
||||||
|
| Signal Direction | Trend Direction | Result | Confidence |
|
||||||
|
|-----------------|----------------|---------|------------|
|
||||||
|
| Long/Short | Same | Execute | High |
|
||||||
|
| Long/Short | Neutral/None | Execute | Medium |
|
||||||
|
| Long/Short | Opposite | Execute* | Low |
|
||||||
|
| None | Long/Short | Execute | Medium/Low |
|
||||||
|
| None | None | No Trade | N/A |
|
||||||
|
|
||||||
|
*_Depends on `AllowSignalTrendOverride` configuration_
|
||||||
|
|
||||||
|
## Configuration Options
|
||||||
|
|
||||||
|
The system uses `StrategyComboConfig` to customize behavior:
|
||||||
|
|
||||||
|
```csharp
|
||||||
|
var config = new StrategyComboConfig
|
||||||
|
{
|
||||||
|
// Trend agreement thresholds
|
||||||
|
TrendStrongAgreementThreshold = 0.66m, // 66% for strong trend
|
||||||
|
|
||||||
|
// Signal agreement thresholds
|
||||||
|
SignalAgreementThreshold = 0.5m, // 50% majority for signals
|
||||||
|
|
||||||
|
// Override behavior
|
||||||
|
AllowSignalTrendOverride = true, // Allow signals to override trends
|
||||||
|
|
||||||
|
// Quality filters
|
||||||
|
MinimumConfidence = Confidence.Low, // Minimum confidence to trade
|
||||||
|
MinimumContextConfidence = Confidence.Medium, // Minimum context quality required
|
||||||
|
|
||||||
|
// Defaults
|
||||||
|
DefaultExchange = TradingExchanges.Binance
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
### Context Strategy Behavior
|
||||||
|
|
||||||
|
Context strategies now work with **confidence levels** rather than allow/block decisions:
|
||||||
|
|
||||||
|
- **High Confidence**: Ideal market conditions (e.g., low volatility)
|
||||||
|
- **Medium Confidence**: Normal market conditions
|
||||||
|
- **Low Confidence**: Elevated risk conditions (trade with caution)
|
||||||
|
- **No Confidence**: Poor conditions (blocks trading)
|
||||||
|
|
||||||
|
All context strategies must meet the `MinimumContextConfidence` threshold for trades to proceed.
|
||||||
|
|
||||||
|
## Usage Examples
|
||||||
|
|
||||||
|
### Basic Usage (Default Configuration)
|
||||||
|
```csharp
|
||||||
|
var signal = TradingBox.GetSignal(candles, strategies, previousSignals);
|
||||||
|
```
|
||||||
|
|
||||||
|
### Advanced Usage (Custom Configuration)
|
||||||
|
```csharp
|
||||||
|
var config = new StrategyComboConfig
|
||||||
|
{
|
||||||
|
TrendStrongAgreementThreshold = 0.75m, // Require 75% trend agreement
|
||||||
|
MinimumConfidence = Confidence.Medium, // Only trade medium+ confidence
|
||||||
|
MinimumContextConfidence = Confidence.High, // Only trade in ideal conditions
|
||||||
|
AllowSignalTrendOverride = false // Don't allow trend conflicts
|
||||||
|
};
|
||||||
|
|
||||||
|
var signal = TradingBox.GetSignal(candles, strategies, previousSignals, config);
|
||||||
|
```
|
||||||
|
|
||||||
|
### Typical Strategy Combinations
|
||||||
|
|
||||||
|
#### Conservative Setup
|
||||||
|
- 1 Signal Strategy (RSI Divergence)
|
||||||
|
- 2 Trend Strategies (EMA Trend, SuperTrend)
|
||||||
|
- 1 Context Strategy (Volatility Filter)
|
||||||
|
|
||||||
|
#### Aggressive Setup
|
||||||
|
- 2 Signal Strategies (MACD Cross, Chandelier Exit)
|
||||||
|
- 1 Trend Strategy (EMA Trend)
|
||||||
|
- No Context Strategies
|
||||||
|
|
||||||
|
#### Scalping Setup
|
||||||
|
- 3 Signal Strategies (Quick signals)
|
||||||
|
- 1 Trend Strategy (Short-term trend)
|
||||||
|
- 2 Context Strategies (Volume + Time filters)
|
||||||
|
|
||||||
|
## Key Improvements
|
||||||
|
|
||||||
|
### 1. **Flexible Requirements**
|
||||||
|
- No longer requires ALL strategies to produce signals
|
||||||
|
- Different logic for different strategy types
|
||||||
|
- Configurable thresholds and behavior
|
||||||
|
|
||||||
|
### 2. **Intelligent Voting**
|
||||||
|
- Majority voting for signals and trends
|
||||||
|
- Weighted decisions based on strategy type
|
||||||
|
- Handles neutral/conflicting signals gracefully
|
||||||
|
|
||||||
|
### 3. **Confidence Scoring**
|
||||||
|
- Dynamic confidence based on agreement levels
|
||||||
|
- Considers signal-trend alignment
|
||||||
|
- Configurable minimum confidence thresholds
|
||||||
|
|
||||||
|
### 4. **Context Awareness**
|
||||||
|
- Context strategies provide market condition quality through confidence levels
|
||||||
|
- Configurable minimum context confidence thresholds
|
||||||
|
- Simplified logic: all context strategies must meet minimum confidence
|
||||||
|
- No more complex unanimous vs. majority requirements
|
||||||
|
|
||||||
|
### 5. **Trend Reversal Support**
|
||||||
|
- Signal strategies can override trend direction
|
||||||
|
- Useful for catching trend reversals
|
||||||
|
- Configurable override behavior
|
||||||
|
|
||||||
|
## Best Practices
|
||||||
|
|
||||||
|
### Strategy Selection
|
||||||
|
1. **Use 1-2 Signal strategies** for entry precision
|
||||||
|
2. **Use 1-3 Trend strategies** for direction confirmation
|
||||||
|
3. **Use 0-2 Context strategies** for risk management
|
||||||
|
|
||||||
|
### Configuration Tuning
|
||||||
|
1. **Start with defaults** and adjust based on backtesting
|
||||||
|
2. **Higher thresholds** = fewer but higher quality signals
|
||||||
|
3. **Lower thresholds** = more signals but potentially more noise
|
||||||
|
|
||||||
|
### Testing Recommendations
|
||||||
|
1. **Backtest different configurations** on historical data
|
||||||
|
2. **Monitor confidence distributions** in live trading
|
||||||
|
3. **Adjust thresholds** based on performance metrics
|
||||||
|
|
||||||
|
## Migration from Old System
|
||||||
|
|
||||||
|
The new system is backward compatible:
|
||||||
|
- Existing calls to `GetSignal()` work unchanged
|
||||||
|
- Old unanimous agreement logic is still available via configuration
|
||||||
|
- New overloads provide additional control when needed
|
||||||
|
|
||||||
|
## Performance Considerations
|
||||||
|
|
||||||
|
- Strategy evaluation is optimized for efficiency
|
||||||
|
- Signal caching prevents duplicate calculations
|
||||||
|
- Configurable quality filters reduce unnecessary trades
|
||||||
|
- Separate validation logic for different strategy types
|
||||||
215
docs/VolatilityControlledTradingScenario.md
Normal file
215
docs/VolatilityControlledTradingScenario.md
Normal file
@@ -0,0 +1,215 @@
|
|||||||
|
# Volatility-Controlled Trading Scenario
|
||||||
|
|
||||||
|
## Overview
|
||||||
|
|
||||||
|
This scenario combines the **STCStrategy** (Signal) with the **StDevContext** (Context) to create a sophisticated trading system that identifies trend reversals while respecting market volatility conditions.
|
||||||
|
|
||||||
|
## Strategy Components
|
||||||
|
|
||||||
|
### STCStrategy (Signal Type)
|
||||||
|
- **Purpose**: Detects trend reversals using Schaff Trend Cycle indicator
|
||||||
|
- **Signals**:
|
||||||
|
- Long when STC crosses above 25 (oversold recovery)
|
||||||
|
- Short when STC crosses below 75 (overbought decline)
|
||||||
|
- **Confidence**: Medium for all signals
|
||||||
|
|
||||||
|
### StDevContext (Context Type)
|
||||||
|
- **Purpose**: Evaluates market volatility to determine trading conditions
|
||||||
|
- **Z-Score Ranges**:
|
||||||
|
- `|Z| ≤ 0.5`: **High Confidence** - Very stable conditions, ideal for trading
|
||||||
|
- `0.5 < |Z| ≤ 1.0`: **Medium Confidence** - Normal volatility, good for trading
|
||||||
|
- `1.0 < |Z| ≤ 1.5`: **Low Confidence** - Elevated volatility, trade with caution
|
||||||
|
- `|Z| > 1.5`: **No Confidence** - High volatility, avoid trading
|
||||||
|
|
||||||
|
## Implementation
|
||||||
|
|
||||||
|
### Basic Setup
|
||||||
|
|
||||||
|
```csharp
|
||||||
|
// Initialize strategies
|
||||||
|
var stcStrategy = new STCStrategy(
|
||||||
|
name: "STC Reversal",
|
||||||
|
cyclePeriods: 10, // Cycle length for STC calculation
|
||||||
|
fastPeriods: 12, // Fast EMA period
|
||||||
|
slowPeriods: 26 // Slow EMA period
|
||||||
|
);
|
||||||
|
|
||||||
|
var volatilityFilter = new StDevContext(
|
||||||
|
name: "Volatility Filter",
|
||||||
|
period: 20 // Period for standard deviation calculation
|
||||||
|
);
|
||||||
|
|
||||||
|
// Set up strategies
|
||||||
|
var strategies = new HashSet<IStrategy> { stcStrategy, volatilityFilter };
|
||||||
|
```
|
||||||
|
|
||||||
|
### Configuration Options
|
||||||
|
|
||||||
|
```csharp
|
||||||
|
// Conservative configuration (safer trading)
|
||||||
|
var conservativeConfig = new StrategyComboConfig
|
||||||
|
{
|
||||||
|
MinimumContextConfidence = Confidence.High, // Only trade in very stable conditions
|
||||||
|
MinimumConfidence = Confidence.Medium, // Only trade medium+ confidence signals
|
||||||
|
AllowSignalTrendOverride = true // Allow reversal signals
|
||||||
|
};
|
||||||
|
|
||||||
|
// Aggressive configuration (more trading opportunities)
|
||||||
|
var aggressiveConfig = new StrategyComboConfig
|
||||||
|
{
|
||||||
|
MinimumContextConfidence = Confidence.Low, // Trade in elevated volatility
|
||||||
|
MinimumConfidence = Confidence.Low, // Accept lower confidence signals
|
||||||
|
AllowSignalTrendOverride = true
|
||||||
|
};
|
||||||
|
|
||||||
|
// Balanced configuration (recommended starting point)
|
||||||
|
var balancedConfig = new StrategyComboConfig
|
||||||
|
{
|
||||||
|
MinimumContextConfidence = Confidence.Medium, // Require normal volatility conditions
|
||||||
|
MinimumConfidence = Confidence.Medium, // Standard confidence requirements
|
||||||
|
AllowSignalTrendOverride = true // Allow trend reversals
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
### Trading Logic
|
||||||
|
|
||||||
|
```csharp
|
||||||
|
public Signal GetTradingSignal(HashSet<Candle> candles, StrategyComboConfig config)
|
||||||
|
{
|
||||||
|
// Update strategies with latest candle data
|
||||||
|
foreach (var strategy in strategies)
|
||||||
|
{
|
||||||
|
strategy.UpdateCandles(candles);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get combined signal
|
||||||
|
var signal = TradingBox.GetSignal(
|
||||||
|
candles,
|
||||||
|
strategies,
|
||||||
|
new HashSet<Signal>(), // Previous signals
|
||||||
|
config,
|
||||||
|
loopbackPeriod: 1 // Check only latest candle
|
||||||
|
);
|
||||||
|
|
||||||
|
return signal;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Complete Example
|
||||||
|
|
||||||
|
```csharp
|
||||||
|
public class VolatilityControlledTradingBot
|
||||||
|
{
|
||||||
|
private readonly STCStrategy _stcStrategy;
|
||||||
|
private readonly StDevContext _volatilityFilter;
|
||||||
|
private readonly StrategyComboConfig _config;
|
||||||
|
|
||||||
|
public VolatilityControlledTradingBot()
|
||||||
|
{
|
||||||
|
_stcStrategy = new STCStrategy("STC Reversal", 10, 12, 26);
|
||||||
|
_volatilityFilter = new StDevContext("Volatility Filter", 20);
|
||||||
|
|
||||||
|
_config = new StrategyComboConfig
|
||||||
|
{
|
||||||
|
MinimumContextConfidence = Confidence.Medium,
|
||||||
|
MinimumConfidence = Confidence.Medium,
|
||||||
|
AllowSignalTrendOverride = true
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<Signal> AnalyzeMarket(List<Candle> candles)
|
||||||
|
{
|
||||||
|
// Ensure we have enough data
|
||||||
|
if (candles.Count < 50) // Need sufficient history for both strategies
|
||||||
|
return null;
|
||||||
|
|
||||||
|
var strategies = new HashSet<IStrategy> { _stcStrategy, _volatilityFilter };
|
||||||
|
|
||||||
|
// Update strategies
|
||||||
|
foreach (var strategy in strategies)
|
||||||
|
{
|
||||||
|
strategy.UpdateCandles(candles.ToHashSet());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get trading signal
|
||||||
|
var signal = TradingBox.GetSignal(
|
||||||
|
candles.ToHashSet(),
|
||||||
|
strategies,
|
||||||
|
new HashSet<Signal>(),
|
||||||
|
_config
|
||||||
|
);
|
||||||
|
|
||||||
|
// Log decision process
|
||||||
|
if (signal != null)
|
||||||
|
{
|
||||||
|
Console.WriteLine($"Trade Signal Generated:");
|
||||||
|
Console.WriteLine($" Direction: {signal.Direction}");
|
||||||
|
Console.WriteLine($" Confidence: {signal.Confidence}");
|
||||||
|
Console.WriteLine($" Date: {signal.Date}");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Console.WriteLine("No trade signal - conditions not met");
|
||||||
|
}
|
||||||
|
|
||||||
|
return signal;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Loopback Period Recommendations
|
||||||
|
|
||||||
|
### For this Scenario:
|
||||||
|
- **Loopback Period: 1-3 candles**
|
||||||
|
- STC reversals are typically captured immediately
|
||||||
|
- Volatility context is current market condition
|
||||||
|
- Short loopback prevents stale signals
|
||||||
|
|
||||||
|
### Considerations:
|
||||||
|
- **Market Timeframe**:
|
||||||
|
- 5m-15m charts: Use loopback = 1
|
||||||
|
- 1h-4h charts: Use loopback = 2-3
|
||||||
|
- Daily charts: Use loopback = 1-2
|
||||||
|
|
||||||
|
## Expected Behavior
|
||||||
|
|
||||||
|
### High Volatility Conditions (Z-Score > 1.5)
|
||||||
|
- StDevContext returns `Confidence.None`
|
||||||
|
- No trades executed regardless of STC signals
|
||||||
|
- Protects against whipsaw movements
|
||||||
|
|
||||||
|
### Normal Volatility Conditions (|Z-Score| ≤ 1.0)
|
||||||
|
- StDevContext returns `Confidence.Medium` or `Confidence.High`
|
||||||
|
- STC signals are evaluated normally
|
||||||
|
- Trades executed when STC crosses thresholds
|
||||||
|
|
||||||
|
### Low Volatility Conditions (|Z-Score| ≤ 0.5)
|
||||||
|
- StDevContext returns `Confidence.High`
|
||||||
|
- Ideal conditions for trend reversal trading
|
||||||
|
- Higher probability of successful STC signals
|
||||||
|
|
||||||
|
## Performance Tuning
|
||||||
|
|
||||||
|
### STC Parameters:
|
||||||
|
- **cyclePeriods**: 8-15 (shorter = more sensitive)
|
||||||
|
- **fastPeriods**: 9-15 (standard EMA settings)
|
||||||
|
- **slowPeriods**: 21-30 (standard EMA settings)
|
||||||
|
|
||||||
|
### Volatility Parameters:
|
||||||
|
- **period**: 14-21 (standard volatility lookback)
|
||||||
|
- **Z-Score thresholds**: Adjust based on asset volatility characteristics
|
||||||
|
|
||||||
|
## Risk Management
|
||||||
|
|
||||||
|
1. **Position Sizing**: Reduce size when volatility confidence is low
|
||||||
|
2. **Stop Losses**: Tighter stops in high volatility periods
|
||||||
|
3. **Take Profits**: Quicker profit-taking when volatility increases
|
||||||
|
4. **Market Hours**: Consider time-based context strategies for optimal trading windows
|
||||||
|
|
||||||
|
## Backtesting Recommendations
|
||||||
|
|
||||||
|
1. Test different volatility thresholds on historical data
|
||||||
|
2. Evaluate performance across various market conditions
|
||||||
|
3. Monitor the distribution of context confidence levels
|
||||||
|
4. Analyze signal quality vs. market volatility correlation
|
||||||
|
5. Compare performance with and without volatility filtering
|
||||||
@@ -7,23 +7,82 @@ using static Managing.Common.Enums;
|
|||||||
|
|
||||||
namespace Managing.Domain.Shared.Helpers;
|
namespace Managing.Domain.Shared.Helpers;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Configuration for strategy combination logic
|
||||||
|
/// </summary>
|
||||||
|
public class StrategyComboConfig
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Minimum percentage of trend strategies that must agree for strong trend (default: 66%)
|
||||||
|
/// </summary>
|
||||||
|
public decimal TrendStrongAgreementThreshold { get; set; } = 0.66m;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Minimum percentage of signal strategies that must agree (default: 50%)
|
||||||
|
/// </summary>
|
||||||
|
public decimal SignalAgreementThreshold { get; set; } = 0.5m;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Whether to allow signal strategies to override conflicting trends (default: true)
|
||||||
|
/// This is useful for trend reversal signals
|
||||||
|
/// </summary>
|
||||||
|
public bool AllowSignalTrendOverride { get; set; } = true;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Minimum confidence level to return a signal (default: Low)
|
||||||
|
/// </summary>
|
||||||
|
public Confidence MinimumConfidence { get; set; } = Confidence.Low;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Minimum confidence level required from context strategies (default: Medium)
|
||||||
|
/// Context strategies evaluate market conditions - higher requirements mean more conservative trading
|
||||||
|
/// </summary>
|
||||||
|
public Confidence MinimumContextConfidence { get; set; } = Confidence.Medium;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Default exchange to use when signals don't specify one
|
||||||
|
/// </summary>
|
||||||
|
public TradingExchanges DefaultExchange { get; set; } = TradingExchanges.Binance;
|
||||||
|
}
|
||||||
|
|
||||||
public static class TradingBox
|
public static class TradingBox
|
||||||
{
|
{
|
||||||
|
private static readonly StrategyComboConfig _defaultConfig = new();
|
||||||
|
|
||||||
public static Signal GetSignal(HashSet<Candle> newCandles, HashSet<IStrategy> strategies,
|
public static Signal GetSignal(HashSet<Candle> newCandles, HashSet<IStrategy> strategies,
|
||||||
HashSet<Signal> previousSignal, int? loopbackPeriod = 1)
|
HashSet<Signal> previousSignal, int? loopbackPeriod = 1)
|
||||||
|
{
|
||||||
|
return GetSignal(newCandles, strategies, previousSignal, _defaultConfig, loopbackPeriod);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Signal GetSignal(HashSet<Candle> newCandles, HashSet<IStrategy> strategies,
|
||||||
|
HashSet<Signal> previousSignal, StrategyComboConfig config, int? loopbackPeriod = 1)
|
||||||
{
|
{
|
||||||
var signalOnCandles = new HashSet<Signal>();
|
var signalOnCandles = new HashSet<Signal>();
|
||||||
var limitedCandles = newCandles.ToList().TakeLast(600).ToList();
|
var limitedCandles = newCandles.ToList().TakeLast(600).ToList();
|
||||||
|
|
||||||
foreach (var strategy in strategies)
|
foreach (var strategy in strategies)
|
||||||
{
|
{
|
||||||
strategy.UpdateCandles(limitedCandles.ToHashSet());
|
strategy.UpdateCandles(limitedCandles.ToHashSet());
|
||||||
var signals = strategy.Run();
|
var signals = strategy.Run();
|
||||||
|
|
||||||
if (signals == null || signals.Count == 0) continue;
|
if (signals == null || signals.Count == 0)
|
||||||
|
{
|
||||||
|
// For trend and context strategies, lack of signal might be meaningful
|
||||||
|
// Signal strategies are expected to be sparse, so we continue
|
||||||
|
if (strategy.SignalType == SignalType.Signal)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// For trend strategies, no signal might mean neutral trend
|
||||||
|
// For context strategies, no signal might mean no restrictions
|
||||||
|
// We'll let the ComputeSignals method handle these cases
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
// Ensure limitedCandles is ordered chronologically
|
// Ensure limitedCandles is ordered chronologically
|
||||||
var orderedCandles = limitedCandles.OrderBy(c => c.Date).ToList();
|
var orderedCandles = limitedCandles.OrderBy(c => c.Date).ToList();
|
||||||
|
|
||||||
var loopback = loopbackPeriod.HasValue && loopbackPeriod > 1 ? loopbackPeriod.Value : 1;
|
var loopback = loopbackPeriod.HasValue && loopbackPeriod > 1 ? loopbackPeriod.Value : 1;
|
||||||
var candleLoopback = orderedCandles.TakeLast(loopback).ToList();
|
var candleLoopback = orderedCandles.TakeLast(loopback).ToList();
|
||||||
|
|
||||||
@@ -49,63 +108,208 @@ public static class TradingBox
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (signalOnCandles.Count != strategies.Count)
|
// Remove the restrictive requirement that ALL strategies must produce signals
|
||||||
return null;
|
// Instead, let ComputeSignals handle the logic based on what we have
|
||||||
|
if (!signalOnCandles.Any())
|
||||||
|
{
|
||||||
|
return null; // No signals from any strategy
|
||||||
|
}
|
||||||
|
|
||||||
var data = newCandles.First();
|
var data = newCandles.First();
|
||||||
return ComputeSignals(strategies, signalOnCandles, MiscExtensions.ParseEnum<Ticker>(data.Ticker),
|
return ComputeSignals(strategies, signalOnCandles, MiscExtensions.ParseEnum<Ticker>(data.Ticker),
|
||||||
data.Timeframe);
|
data.Timeframe, config);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Signal ComputeSignals(HashSet<IStrategy> strategies, HashSet<Signal> signalOnCandles, Ticker ticker,
|
public static Signal ComputeSignals(HashSet<IStrategy> strategies, HashSet<Signal> signalOnCandles, Ticker ticker,
|
||||||
Timeframe timeframe)
|
Timeframe timeframe)
|
||||||
{
|
{
|
||||||
Signal signal = null;
|
return ComputeSignals(strategies, signalOnCandles, ticker, timeframe, _defaultConfig);
|
||||||
if (strategies.Count > 1)
|
}
|
||||||
{
|
|
||||||
var trendSignal = signalOnCandles.Where(s => s.SignalType == SignalType.Trend).ToList();
|
|
||||||
var signals = signalOnCandles.Where(s => s.SignalType == SignalType.Signal).ToList();
|
|
||||||
var contextStrategiesCount = strategies.Count(s => s.SignalType == SignalType.Context);
|
|
||||||
var validContext = true;
|
|
||||||
|
|
||||||
if (contextStrategiesCount > 0 &&
|
public static Signal ComputeSignals(HashSet<IStrategy> strategies, HashSet<Signal> signalOnCandles, Ticker ticker,
|
||||||
signalOnCandles.Count(s => s.SignalType == SignalType.Context) != contextStrategiesCount)
|
Timeframe timeframe, StrategyComboConfig config)
|
||||||
{
|
{
|
||||||
validContext = false;
|
if (strategies.Count == 1)
|
||||||
}
|
|
||||||
|
|
||||||
if (signals.All(s => s.Direction == TradeDirection.Long) &&
|
|
||||||
trendSignal.All(t => t.Direction == TradeDirection.Long) && validContext)
|
|
||||||
{
|
|
||||||
signal = new Signal(
|
|
||||||
ticker,
|
|
||||||
TradeDirection.Long,
|
|
||||||
Confidence.High,
|
|
||||||
signals.Last().Candle,
|
|
||||||
signals.Last().Date,
|
|
||||||
signals.Last().Exchange,
|
|
||||||
StrategyType.Composite, SignalType.Signal);
|
|
||||||
}
|
|
||||||
else if (signals.All(s => s.Direction == TradeDirection.Short) &&
|
|
||||||
trendSignal.All(t => t.Direction == TradeDirection.Short) && validContext)
|
|
||||||
{
|
|
||||||
signal = new Signal(
|
|
||||||
ticker,
|
|
||||||
TradeDirection.Short,
|
|
||||||
Confidence.High,
|
|
||||||
signals.Last().Candle,
|
|
||||||
signals.Last().Date,
|
|
||||||
signals.Last().Exchange,
|
|
||||||
StrategyType.Composite, SignalType.Signal);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
{
|
||||||
// Only one strategy, we just add the single signal to the bot
|
// Only one strategy, return the single signal
|
||||||
signal = signalOnCandles.Single();
|
return signalOnCandles.Single();
|
||||||
}
|
}
|
||||||
|
|
||||||
return signal;
|
// Group signals by type for analysis
|
||||||
|
var signalStrategies = signalOnCandles.Where(s => s.SignalType == SignalType.Signal).ToList();
|
||||||
|
var trendStrategies = signalOnCandles.Where(s => s.SignalType == SignalType.Trend).ToList();
|
||||||
|
var contextStrategies = signalOnCandles.Where(s => s.SignalType == SignalType.Context).ToList();
|
||||||
|
|
||||||
|
// Context validation - evaluates market conditions based on confidence levels
|
||||||
|
if (!ValidateContextStrategies(strategies, contextStrategies, config))
|
||||||
|
{
|
||||||
|
return null; // Context strategies are blocking the trade
|
||||||
|
}
|
||||||
|
|
||||||
|
// Trend analysis - evaluate overall market direction
|
||||||
|
var trendDirection = EvaluateTrendDirection(trendStrategies, config);
|
||||||
|
|
||||||
|
// Signal analysis - evaluate entry signals
|
||||||
|
var signalDirection = EvaluateSignalDirection(signalStrategies, config);
|
||||||
|
|
||||||
|
// Determine final direction and confidence
|
||||||
|
var (finalDirection, confidence) = DetermineFinalSignal(signalDirection, trendDirection, signalStrategies, trendStrategies, config);
|
||||||
|
|
||||||
|
if (finalDirection == TradeDirection.None || confidence < config.MinimumConfidence)
|
||||||
|
{
|
||||||
|
return null; // No valid signal or below minimum confidence
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create composite signal
|
||||||
|
var lastSignal = signalStrategies.LastOrDefault() ?? trendStrategies.LastOrDefault() ?? contextStrategies.LastOrDefault();
|
||||||
|
|
||||||
|
return new Signal(
|
||||||
|
ticker,
|
||||||
|
finalDirection,
|
||||||
|
confidence,
|
||||||
|
lastSignal?.Candle,
|
||||||
|
lastSignal?.Date ?? DateTime.UtcNow,
|
||||||
|
lastSignal?.Exchange ?? config.DefaultExchange,
|
||||||
|
StrategyType.Composite,
|
||||||
|
SignalType.Signal);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Validates context strategies based on confidence levels indicating market condition quality
|
||||||
|
/// </summary>
|
||||||
|
private static bool ValidateContextStrategies(HashSet<IStrategy> allStrategies, List<Signal> contextSignals, StrategyComboConfig config)
|
||||||
|
{
|
||||||
|
var contextStrategiesCount = allStrategies.Count(s => s.SignalType == SignalType.Context);
|
||||||
|
|
||||||
|
if (contextStrategiesCount == 0)
|
||||||
|
{
|
||||||
|
return true; // No context strategies, no restrictions
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if we have signals from all context strategies
|
||||||
|
if (contextSignals.Count != contextStrategiesCount)
|
||||||
|
{
|
||||||
|
return false; // Missing context information
|
||||||
|
}
|
||||||
|
|
||||||
|
// All context strategies must meet minimum confidence requirements
|
||||||
|
// This ensures market conditions are suitable for trading
|
||||||
|
return contextSignals.All(s => s.Confidence >= config.MinimumContextConfidence);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Evaluates trend direction using majority voting with neutral handling
|
||||||
|
/// </summary>
|
||||||
|
private static TradeDirection EvaluateTrendDirection(List<Signal> trendSignals, StrategyComboConfig config)
|
||||||
|
{
|
||||||
|
if (!trendSignals.Any())
|
||||||
|
{
|
||||||
|
return TradeDirection.None; // No trend information available
|
||||||
|
}
|
||||||
|
|
||||||
|
var longCount = trendSignals.Count(s => s.Direction == TradeDirection.Long);
|
||||||
|
var shortCount = trendSignals.Count(s => s.Direction == TradeDirection.Short);
|
||||||
|
var neutralCount = trendSignals.Count(s => s.Direction == TradeDirection.None);
|
||||||
|
|
||||||
|
// Strong trend agreement using configurable threshold
|
||||||
|
var totalTrend = trendSignals.Count;
|
||||||
|
if (longCount > totalTrend * config.TrendStrongAgreementThreshold)
|
||||||
|
return TradeDirection.Long;
|
||||||
|
if (shortCount > totalTrend * config.TrendStrongAgreementThreshold)
|
||||||
|
return TradeDirection.Short;
|
||||||
|
|
||||||
|
// Moderate trend agreement (> 50% but <= strong threshold)
|
||||||
|
if (longCount > shortCount && longCount > neutralCount)
|
||||||
|
return TradeDirection.Long;
|
||||||
|
if (shortCount > longCount && shortCount > neutralCount)
|
||||||
|
return TradeDirection.Short;
|
||||||
|
|
||||||
|
// No clear trend or too many neutrals
|
||||||
|
return TradeDirection.None;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Evaluates signal direction using weighted majority voting
|
||||||
|
/// </summary>
|
||||||
|
private static TradeDirection EvaluateSignalDirection(List<Signal> signalStrategies, StrategyComboConfig config)
|
||||||
|
{
|
||||||
|
if (!signalStrategies.Any())
|
||||||
|
{
|
||||||
|
return TradeDirection.None; // No signal strategies
|
||||||
|
}
|
||||||
|
|
||||||
|
// For signal strategies, we need stronger agreement since they're rare and should be precise
|
||||||
|
var longCount = signalStrategies.Count(s => s.Direction == TradeDirection.Long);
|
||||||
|
var shortCount = signalStrategies.Count(s => s.Direction == TradeDirection.Short);
|
||||||
|
|
||||||
|
// Use configurable agreement threshold for signals
|
||||||
|
var totalSignals = signalStrategies.Count;
|
||||||
|
if (longCount > totalSignals * config.SignalAgreementThreshold)
|
||||||
|
return TradeDirection.Long;
|
||||||
|
if (shortCount > totalSignals * config.SignalAgreementThreshold)
|
||||||
|
return TradeDirection.Short;
|
||||||
|
|
||||||
|
return TradeDirection.None;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Determines final signal direction and confidence based on signal and trend analysis
|
||||||
|
/// </summary>
|
||||||
|
private static (TradeDirection Direction, Confidence Confidence) DetermineFinalSignal(
|
||||||
|
TradeDirection signalDirection,
|
||||||
|
TradeDirection trendDirection,
|
||||||
|
List<Signal> signalStrategies,
|
||||||
|
List<Signal> trendStrategies,
|
||||||
|
StrategyComboConfig config)
|
||||||
|
{
|
||||||
|
// Priority 1: If we have signal strategies, they take precedence
|
||||||
|
if (signalDirection != TradeDirection.None)
|
||||||
|
{
|
||||||
|
// Signal strategies have fired - check if trend supports or conflicts
|
||||||
|
if (trendDirection == signalDirection)
|
||||||
|
{
|
||||||
|
// Perfect alignment - signal and trend agree
|
||||||
|
return (signalDirection, Confidence.High);
|
||||||
|
}
|
||||||
|
else if (trendDirection == TradeDirection.None)
|
||||||
|
{
|
||||||
|
// No trend information or neutral trend - medium confidence
|
||||||
|
return (signalDirection, Confidence.Medium);
|
||||||
|
}
|
||||||
|
else if (config.AllowSignalTrendOverride)
|
||||||
|
{
|
||||||
|
// Trend conflicts with signal but we allow override
|
||||||
|
// This could be a trend reversal signal
|
||||||
|
return (signalDirection, Confidence.Low);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Trend conflicts and we don't allow override
|
||||||
|
return (TradeDirection.None, Confidence.None);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Priority 2: Only trend strategies available
|
||||||
|
if (trendDirection != TradeDirection.None)
|
||||||
|
{
|
||||||
|
// Calculate confidence based on trend strength
|
||||||
|
var totalTrend = trendStrategies.Count;
|
||||||
|
var majorityDirection = trendDirection == TradeDirection.Long
|
||||||
|
? trendStrategies.Count(s => s.Direction == TradeDirection.Long)
|
||||||
|
: trendStrategies.Count(s => s.Direction == TradeDirection.Short);
|
||||||
|
|
||||||
|
var agreementPercentage = (decimal)majorityDirection / totalTrend;
|
||||||
|
|
||||||
|
if (agreementPercentage >= 0.8m)
|
||||||
|
return (trendDirection, Confidence.High);
|
||||||
|
else if (agreementPercentage >= config.TrendStrongAgreementThreshold)
|
||||||
|
return (trendDirection, Confidence.Medium);
|
||||||
|
else
|
||||||
|
return (trendDirection, Confidence.Low);
|
||||||
|
}
|
||||||
|
|
||||||
|
// No valid signal found
|
||||||
|
return (TradeDirection.None, Confidence.None);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static MoneyManagement GetBestMoneyManagement(List<Candle> candles, List<Position> positions,
|
public static MoneyManagement GetBestMoneyManagement(List<Candle> candles, List<Position> positions,
|
||||||
|
|||||||
@@ -33,16 +33,38 @@ public class StDevContext : Strategy
|
|||||||
return null;
|
return null;
|
||||||
|
|
||||||
var lastCandle = stDevCandles.Last();
|
var lastCandle = stDevCandles.Last();
|
||||||
|
var zScore = lastCandle.ZScore ?? 0;
|
||||||
|
|
||||||
if (lastCandle.ZScore is < 1.2 and > (-1.2))
|
// Determine confidence based on Z-score ranges
|
||||||
|
// Lower absolute Z-score = more normal volatility = higher confidence for trading
|
||||||
|
// Higher absolute Z-score = more extreme volatility = lower confidence for trading
|
||||||
|
Confidence confidence;
|
||||||
|
|
||||||
|
if (Math.Abs(zScore) <= 0.5)
|
||||||
{
|
{
|
||||||
AddSignal(lastCandle, TradeDirection.None, Confidence.Medium);
|
// Very low volatility - ideal conditions for trading
|
||||||
|
confidence = Confidence.High;
|
||||||
|
}
|
||||||
|
else if (Math.Abs(zScore) <= 1.0)
|
||||||
|
{
|
||||||
|
// Normal volatility - good conditions for trading
|
||||||
|
confidence = Confidence.Medium;
|
||||||
|
}
|
||||||
|
else if (Math.Abs(zScore) <= 1.5)
|
||||||
|
{
|
||||||
|
// Elevated volatility - caution advised
|
||||||
|
confidence = Confidence.Low;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Console.WriteLine("Bad zscore");
|
// High volatility - trading not recommended
|
||||||
|
confidence = Confidence.None;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Context strategies always return TradeDirection.None
|
||||||
|
// The confidence level indicates the quality of market conditions
|
||||||
|
AddSignal(lastCandle, TradeDirection.None, confidence);
|
||||||
|
|
||||||
return Signals.Where(s => s.Confidence != Confidence.None).OrderBy(s => s.Date).ToList();
|
return Signals.Where(s => s.Confidence != Confidence.None).OrderBy(s => s.Date).ToList();
|
||||||
}
|
}
|
||||||
catch (RuleException)
|
catch (RuleException)
|
||||||
|
|||||||
@@ -6,7 +6,6 @@ using Managing.Application.Abstractions;
|
|||||||
using Managing.Application.Abstractions.Services;
|
using Managing.Application.Abstractions.Services;
|
||||||
using Managing.Application.Trading;
|
using Managing.Application.Trading;
|
||||||
using Managing.Application.Trading.Commands;
|
using Managing.Application.Trading.Commands;
|
||||||
using Managing.Application.Workers.Abstractions;
|
|
||||||
using Managing.Common;
|
using Managing.Common;
|
||||||
using Managing.Core;
|
using Managing.Core;
|
||||||
using Managing.Domain.MoneyManagements;
|
using Managing.Domain.MoneyManagements;
|
||||||
@@ -294,7 +293,7 @@ namespace Managing.Infrastructure.Messengers.Discord
|
|||||||
$"Open Price : {position.Open.Price} \n" +
|
$"Open Price : {position.Open.Price} \n" +
|
||||||
$"Closing Price : {position.Open.Price} \n" +
|
$"Closing Price : {position.Open.Price} \n" +
|
||||||
$"Quantity :{position.Open.Quantity} \n" +
|
$"Quantity :{position.Open.Quantity} \n" +
|
||||||
$"PNL : {position.ProfitAndLoss.Net} $";
|
$"PNL : {position.ProfitAndLoss.Realized} $";
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task ClosePosition(SocketMessageComponent component, string[] parameters)
|
private async Task ClosePosition(SocketMessageComponent component, string[] parameters)
|
||||||
|
|||||||
8
src/Managing.Web3Proxy/package-lock.json
generated
8
src/Managing.Web3Proxy/package-lock.json
generated
@@ -4340,7 +4340,7 @@
|
|||||||
},
|
},
|
||||||
"node_modules/get-tsconfig": {
|
"node_modules/get-tsconfig": {
|
||||||
"version": "4.10.0",
|
"version": "4.10.0",
|
||||||
"dev": true,
|
"devOptional": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"resolve-pkg-maps": "^1.0.0"
|
"resolve-pkg-maps": "^1.0.0"
|
||||||
@@ -6598,7 +6598,7 @@
|
|||||||
},
|
},
|
||||||
"node_modules/resolve-pkg-maps": {
|
"node_modules/resolve-pkg-maps": {
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"dev": true,
|
"devOptional": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"funding": {
|
"funding": {
|
||||||
"url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1"
|
"url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1"
|
||||||
@@ -7526,7 +7526,7 @@
|
|||||||
},
|
},
|
||||||
"node_modules/tsx": {
|
"node_modules/tsx": {
|
||||||
"version": "4.19.3",
|
"version": "4.19.3",
|
||||||
"dev": true,
|
"devOptional": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"esbuild": "~0.25.0",
|
"esbuild": "~0.25.0",
|
||||||
@@ -7646,7 +7646,7 @@
|
|||||||
},
|
},
|
||||||
"node_modules/typescript": {
|
"node_modules/typescript": {
|
||||||
"version": "5.8.2",
|
"version": "5.8.2",
|
||||||
"dev": true,
|
"devOptional": true,
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
"bin": {
|
"bin": {
|
||||||
"tsc": "bin/tsc",
|
"tsc": "bin/tsc",
|
||||||
|
|||||||
@@ -212,13 +212,14 @@ export const openGmxPositionImpl = async (
|
|||||||
marketAddress: marketInfo.marketTokenAddress,
|
marketAddress: marketInfo.marketTokenAddress,
|
||||||
payTokenAddress: collateralToken.address,
|
payTokenAddress: collateralToken.address,
|
||||||
collateralTokenAddress: collateralToken.address,
|
collateralTokenAddress: collateralToken.address,
|
||||||
allowedSlippageBps: 100, // 0.5% slippage
|
allowedSlippageBps: 50, // 0.5% slippage
|
||||||
leverage: leverageBps,
|
leverage: leverageBps,
|
||||||
skipSimulation: true,
|
skipSimulation: true,
|
||||||
referralCodeForTxn: encodeReferralCode("kaigen_ai"),
|
referralCodeForTxn: encodeReferralCode("kaigen_ai"),
|
||||||
stopLossPrice: stopLossPrice ? numberToBigint(stopLossPrice, 30) : undefined,
|
stopLossPrice: stopLossPrice ? numberToBigint(stopLossPrice, 30) : undefined,
|
||||||
takeProfitPrice: takeProfitPrice ? numberToBigint(takeProfitPrice, 30) : undefined,
|
takeProfitPrice: takeProfitPrice ? numberToBigint(takeProfitPrice, 30) : undefined,
|
||||||
acceptablePriceImpactBuffer: 150,
|
acceptablePriceImpactBuffer: 150,
|
||||||
|
limitPrice: limitPrice,
|
||||||
};
|
};
|
||||||
|
|
||||||
if (direction === TradeDirection.Long) {
|
if (direction === TradeDirection.Long) {
|
||||||
|
|||||||
@@ -65,7 +65,7 @@ const CustomMoneyManagement: React.FC<ICustomMoneyManagement> = ({
|
|||||||
value={takeProfit}
|
value={takeProfit}
|
||||||
onChange={(e: any) => setTakeProfit(e.target.value)}
|
onChange={(e: any) => setTakeProfit(e.target.value)}
|
||||||
step="0.01"
|
step="0.01"
|
||||||
max="20"
|
max="100"
|
||||||
type='number'
|
type='number'
|
||||||
className='input input-bordered'
|
className='input input-bordered'
|
||||||
></input>
|
></input>
|
||||||
@@ -77,7 +77,7 @@ const CustomMoneyManagement: React.FC<ICustomMoneyManagement> = ({
|
|||||||
value={stopLoss}
|
value={stopLoss}
|
||||||
onChange={(e: any) => setStopLoss(e.target.value)}
|
onChange={(e: any) => setStopLoss(e.target.value)}
|
||||||
step="0.01"
|
step="0.01"
|
||||||
max="20"
|
max="100"
|
||||||
type='number'
|
type='number'
|
||||||
className='input input-bordered'
|
className='input input-bordered'
|
||||||
></input>
|
></input>
|
||||||
|
|||||||
@@ -169,6 +169,20 @@ const TradeChart = ({
|
|||||||
chart.current = createChart(chartRef.current, {
|
chart.current = createChart(chartRef.current, {
|
||||||
crosshair: {
|
crosshair: {
|
||||||
mode: CrosshairMode.Normal,
|
mode: CrosshairMode.Normal,
|
||||||
|
vertLine: {
|
||||||
|
color: theme.accent,
|
||||||
|
width: 1,
|
||||||
|
style: LineStyle.Solid,
|
||||||
|
visible: true,
|
||||||
|
labelVisible: true,
|
||||||
|
},
|
||||||
|
horzLine: {
|
||||||
|
color: theme.accent,
|
||||||
|
width: 1,
|
||||||
|
style: LineStyle.Solid,
|
||||||
|
visible: true,
|
||||||
|
labelVisible: true,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
grid: {
|
grid: {
|
||||||
horzLines: {
|
horzLines: {
|
||||||
@@ -334,6 +348,7 @@ const TradeChart = ({
|
|||||||
priceLineColor: theme.info,
|
priceLineColor: theme.info,
|
||||||
title: 'SuperTrend',
|
title: 'SuperTrend',
|
||||||
pane: 0,
|
pane: 0,
|
||||||
|
|
||||||
})
|
})
|
||||||
|
|
||||||
const superTrend = strategiesValues.SuperTrend.superTrend?.map((w) => {
|
const superTrend = strategiesValues.SuperTrend.superTrend?.map((w) => {
|
||||||
@@ -409,6 +424,7 @@ const TradeChart = ({
|
|||||||
precision: 1,
|
precision: 1,
|
||||||
type: 'price',
|
type: 'price',
|
||||||
},
|
},
|
||||||
|
crosshairMarkerVisible: true,
|
||||||
})
|
})
|
||||||
|
|
||||||
paneCount++
|
paneCount++
|
||||||
@@ -453,6 +469,7 @@ const TradeChart = ({
|
|||||||
precision: 6,
|
precision: 6,
|
||||||
type: 'price',
|
type: 'price',
|
||||||
},
|
},
|
||||||
|
crosshairMarkerVisible: true,
|
||||||
})
|
})
|
||||||
|
|
||||||
const macdData = strategiesValues.MacdCross.macd?.map((w) => {
|
const macdData = strategiesValues.MacdCross.macd?.map((w) => {
|
||||||
@@ -537,6 +554,7 @@ const TradeChart = ({
|
|||||||
baseValue: {price: 0, type: 'price'},
|
baseValue: {price: 0, type: 'price'},
|
||||||
title: 'ZScore',
|
title: 'ZScore',
|
||||||
pane: paneCount,
|
pane: paneCount,
|
||||||
|
crosshairMarkerVisible: true,
|
||||||
})
|
})
|
||||||
|
|
||||||
const zScore = strategiesValues.StDev.stdDev?.map((w) => {
|
const zScore = strategiesValues.StDev.stdDev?.map((w) => {
|
||||||
|
|||||||
Reference in New Issue
Block a user