Pronóstico de Rango Monte Carlo
El Pronóstico de Rango Monte Carlo utiliza simulaciones Monte Carlo con volatilidad basada en ATR para proyectar el rango futuro de precios. La estrategia entra en largo cuando el precio simulado promedio supera el precio actual y entra en corto cuando cae por debajo.
Detalles
- Datos: Velas de precio con ATR.
- Criterios de entrada:
- Largo: El precio esperado de las simulaciones está por encima del precio actual.
- Corto: El precio esperado de las simulaciones está por debajo del precio actual.
- Criterios de salida: Señal opuesta.
- Stops: Ninguno.
- Valores predeterminados:
ForecastPeriod= 20Simulations= 100
- Filtros:
- Categoría: Estadística
- Dirección: Largo y Corto
- Indicadores: ATR
- Complejidad: Moderado
- Nivel de riesgo: Medio
using System;
using System.Linq;
using Ecng.Common;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// Strategy using Monte Carlo simulation to forecast price range.
/// </summary>
public class MonteCarloRangeForecastStrategy : Strategy
{
private readonly StrategyParam<int> _forecastPeriod;
private readonly StrategyParam<int> _simulations;
private readonly StrategyParam<decimal> _minForecastEdgePercent;
private readonly StrategyParam<int> _signalCooldownBars;
private readonly StrategyParam<DataType> _candleType;
private int _barsFromSignal;
public int ForecastPeriod { get => _forecastPeriod.Value; set => _forecastPeriod.Value = value; }
public int Simulations { get => _simulations.Value; set => _simulations.Value = value; }
public decimal MinForecastEdgePercent { get => _minForecastEdgePercent.Value; set => _minForecastEdgePercent.Value = value; }
public int SignalCooldownBars { get => _signalCooldownBars.Value; set => _signalCooldownBars.Value = value; }
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public MonteCarloRangeForecastStrategy()
{
_forecastPeriod = Param(nameof(ForecastPeriod), 20).SetGreaterThanZero();
_simulations = Param(nameof(Simulations), 100).SetGreaterThanZero();
_minForecastEdgePercent = Param(nameof(MinForecastEdgePercent), 0.25m).SetGreaterThanZero();
_signalCooldownBars = Param(nameof(SignalCooldownBars), 10).SetGreaterThanZero();
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(15).TimeFrame());
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_barsFromSignal = 0;
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
StartProtection(null, null);
_barsFromSignal = SignalCooldownBars;
var atr = new AverageTrueRange { Length = 14 };
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(atr, ProcessCandle)
.Start();
}
private void ProcessCandle(ICandleMessage candle, decimal atr)
{
if (candle.State != CandleStates.Finished)
return;
if (!IsFormedAndOnlineAndAllowTrading())
return;
var current = candle.ClosePrice;
if (current <= 0m || atr <= 0m)
return;
_barsFromSignal++;
var stepVol = atr / current;
double sum = 0.0;
var random = new Random(unchecked((int)candle.OpenTime.Ticks));
for (var i = 0; i < Simulations; i++)
{
var price = current;
for (var j = 0; j < ForecastPeriod; j++)
{
var rnd = NextGaussian(random);
price += price * stepVol * rnd;
}
sum += (double)price;
}
var mean = sum / Simulations;
var edgePercent = (decimal)((mean - (double)current) / (double)current * 100d);
if (_barsFromSignal >= SignalCooldownBars && edgePercent >= MinForecastEdgePercent && Position <= 0)
{
BuyMarket();
_barsFromSignal = 0;
}
else if (_barsFromSignal >= SignalCooldownBars && edgePercent <= -MinForecastEdgePercent && Position >= 0)
{
SellMarket();
_barsFromSignal = 0;
}
}
private static decimal NextGaussian(Random random)
{
var u1 = 1.0 - random.NextDouble();
var u2 = 1.0 - random.NextDouble();
return (decimal)(Math.Sqrt(-2.0 * Math.Log(u1)) * Math.Cos(2.0 * Math.PI * u2));
}
}
import clr
import math
import random
clr.AddReference("StockSharp.Messages")
clr.AddReference("StockSharp.Algo")
clr.AddReference("StockSharp.Algo.Indicators")
clr.AddReference("StockSharp.Algo.Strategies")
from System import TimeSpan
from StockSharp.Messages import DataType, CandleStates
from StockSharp.Algo.Indicators import AverageTrueRange
from StockSharp.Algo.Strategies import Strategy
class monte_carlo_range_forecast_strategy(Strategy):
"""
Monte Carlo simulation to forecast price range using ATR-based volatility.
"""
def __init__(self):
super(monte_carlo_range_forecast_strategy, self).__init__()
self._forecast_period = self.Param("ForecastPeriod", 20).SetDisplay("Forecast Period", "Forecast horizon", "General")
self._simulations = self.Param("Simulations", 100).SetDisplay("Simulations", "Number of MC sims", "General")
self._min_edge_pct = self.Param("MinForecastEdgePercent", 0.25).SetDisplay("Min Edge %", "Min forecast edge", "General")
self._cooldown_bars = self.Param("SignalCooldownBars", 10).SetDisplay("Cooldown", "Min bars between entries", "General")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(15))).SetDisplay("Candle Type", "Candles", "General")
self._bars_from_signal = 10
@property
def candle_type(self):
return self._candle_type.Value
def OnReseted(self):
super(monte_carlo_range_forecast_strategy, self).OnReseted()
self._bars_from_signal = self._cooldown_bars.Value
def OnStarted2(self, time):
super(monte_carlo_range_forecast_strategy, self).OnStarted2(time)
atr = AverageTrueRange()
atr.Length = 14
subscription = self.SubscribeCandles(self.candle_type)
subscription.Bind(atr, self._process_candle).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawIndicator(area, atr)
self.DrawOwnTrades(area)
def _process_candle(self, candle, atr_val):
if candle.State != CandleStates.Finished:
return
current = float(candle.ClosePrice)
atr = float(atr_val)
if current <= 0 or atr <= 0:
return
self._bars_from_signal += 1
step_vol = atr / current
total = 0.0
sims = self._simulations.Value
fp = self._forecast_period.Value
ticks = int(candle.OpenTime.Ticks)
seed = ticks & 0xFFFFFFFF
if seed > 0x7FFFFFFF:
seed -= 0x100000000
rng = random.Random(int(seed))
for i in range(sims):
price = current
for j in range(fp):
u1 = 1.0 - rng.random()
u2 = 1.0 - rng.random()
g = math.sqrt(-2.0 * math.log(u1)) * math.cos(2.0 * math.pi * u2)
price += price * step_vol * g
total += price
mean = total / sims
edge_pct = (mean - current) / current * 100.0
min_edge = float(self._min_edge_pct.Value)
if self._bars_from_signal >= self._cooldown_bars.Value and edge_pct >= min_edge and self.Position <= 0:
self.BuyMarket()
self._bars_from_signal = 0
elif self._bars_from_signal >= self._cooldown_bars.Value and edge_pct <= -min_edge and self.Position >= 0:
self.SellMarket()
self._bars_from_signal = 0
def CreateClone(self):
return monte_carlo_range_forecast_strategy()