Javo v1 策略
Javo v1 将 Heikin Ashi 蜡烛与两条 EMA 结合。当 HA 方向与快慢 EMA 的交叉一致时开仓,旨在捕捉新出现的趋势并减少噪声。
详情
- 入场条件:
- 多头: HA 看涨且
EMA_fast > EMA_slow - 空头: HA 看跌且
EMA_fast < EMA_slow
- 多头: HA 看涨且
- 多空方向: 双向
- 退出条件: 反向信号
- 止损: 无
- 默认值:
FastEmaPeriod= 1SlowEmaPeriod= 30
- 过滤器:
- 类型: 趋势跟随
- 方向: 双向
- 指标: Heikin Ashi, EMA
- 止损: 无
- 复杂度: 低
- 时间框架: 小时级
- 季节性: 否
- 神经网络: 否
- 背离: 否
- 风险等级: 中等
using System;
using System.Collections.Generic;
using Ecng.Common;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// Javo v1 strategy.
/// Builds Heikin Ashi candles and runs a fast and a slow EMA on the Heikin Ashi close. Goes long when the Heikin Ashi
/// candle is bullish and the fast EMA is above the slow one, short when the candle is bearish and the fast EMA is below
/// the slow one. The opposite signal reverses the position.
/// </summary>
public class JavoV1Strategy : Strategy
{
private readonly StrategyParam<int> _fastEmaPeriod;
private readonly StrategyParam<int> _slowEmaPeriod;
private readonly StrategyParam<DataType> _candleType;
private ExponentialMovingAverage _fastEma;
private ExponentialMovingAverage _slowEma;
private decimal? _prevHaOpen;
private decimal? _prevHaClose;
/// <summary>
/// Fast EMA period.
/// </summary>
public int FastEmaPeriod
{
get => _fastEmaPeriod.Value;
set => _fastEmaPeriod.Value = value;
}
/// <summary>
/// Slow EMA period.
/// </summary>
public int SlowEmaPeriod
{
get => _slowEmaPeriod.Value;
set => _slowEmaPeriod.Value = value;
}
/// <summary>
/// Candle type for strategy calculation.
/// </summary>
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
/// <summary>
/// Constructor.
/// </summary>
public JavoV1Strategy()
{
_fastEmaPeriod = Param(nameof(FastEmaPeriod), 1)
.SetGreaterThanZero()
.SetDisplay("Fast EMA", "Fast EMA period on the Heikin Ashi close", "Moving Averages");
_slowEmaPeriod = Param(nameof(SlowEmaPeriod), 30)
.SetGreaterThanZero()
.SetDisplay("Slow EMA", "Slow EMA period on the Heikin Ashi close", "Moving Averages");
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(1).TimeFrame())
.SetDisplay("Candle type", "Candle type for strategy calculation", "General");
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
=> [(Security, CandleType)];
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_fastEma = null;
_slowEma = null;
_prevHaOpen = null;
_prevHaClose = null;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_prevHaOpen = null;
_prevHaClose = null;
_fastEma = new ExponentialMovingAverage { Length = FastEmaPeriod };
_slowEma = new ExponentialMovingAverage { Length = SlowEmaPeriod };
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(ProcessCandle)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, _fastEma);
DrawIndicator(area, _slowEma);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle)
{
if (candle.State != CandleStates.Finished)
return;
var haClose = (candle.OpenPrice + candle.HighPrice + candle.LowPrice + candle.ClosePrice) / 4m;
var haOpen = _prevHaOpen is decimal prevOpen && _prevHaClose is decimal prevClose
? (prevOpen + prevClose) / 2m
: (candle.OpenPrice + candle.ClosePrice) / 2m;
_prevHaOpen = haOpen;
_prevHaClose = haClose;
var fast = _fastEma.Process(haClose, candle.ServerTime, true).ToDecimal();
var slow = _slowEma.Process(haClose, candle.ServerTime, true).ToDecimal();
if (!_fastEma.IsFormed || !_slowEma.IsFormed)
return;
if (!IsFormedAndOnlineAndAllowTrading())
return;
if (haClose > haOpen && fast > slow && Position <= 0)
BuyMarket(Volume + Math.Abs(Position));
else if (haClose < haOpen && fast < slow && Position >= 0)
SellMarket(Volume + Math.Abs(Position));
}
}
import clr
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 ExponentialMovingAverage
from StockSharp.Algo.Strategies import Strategy
from indicator_extensions import *
class javo_v1_strategy(Strategy):
"""
Javo v1 strategy.
Builds Heikin Ashi candles and runs a fast and a slow EMA on the Heikin Ashi close. Goes long when the Heikin Ashi
candle is bullish and the fast EMA is above the slow one, short when the candle is bearish and the fast EMA is below
the slow one. The opposite signal reverses the position.
"""
def __init__(self):
super(javo_v1_strategy, self).__init__()
self._fast_ema_period = self.Param("FastEmaPeriod", 1) \
.SetGreaterThanZero() \
.SetDisplay("Fast EMA", "Fast EMA period on the Heikin Ashi close", "Moving Averages")
self._slow_ema_period = self.Param("SlowEmaPeriod", 30) \
.SetGreaterThanZero() \
.SetDisplay("Slow EMA", "Slow EMA period on the Heikin Ashi close", "Moving Averages")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(1))) \
.SetDisplay("Candle type", "Candle type for strategy calculation", "General")
self._fast_ema = None
self._slow_ema = None
self._prev_ha_open = None
self._prev_ha_close = None
@property
def CandleType(self):
return self._candle_type.Value
def GetWorkingSecurities(self):
return [(self.Security, self.CandleType)]
def OnReseted(self):
super(javo_v1_strategy, self).OnReseted()
self._fast_ema = None
self._slow_ema = None
self._prev_ha_open = None
self._prev_ha_close = None
def OnStarted2(self, time):
super(javo_v1_strategy, self).OnStarted2(time)
self._prev_ha_open = None
self._prev_ha_close = None
self._fast_ema = ExponentialMovingAverage()
self._fast_ema.Length = self._fast_ema_period.Value
self._slow_ema = ExponentialMovingAverage()
self._slow_ema.Length = self._slow_ema_period.Value
subscription = self.SubscribeCandles(self.CandleType)
subscription.Bind(self._process_candle).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawIndicator(area, self._fast_ema)
self.DrawIndicator(area, self._slow_ema)
self.DrawOwnTrades(area)
def _process_candle(self, candle):
if candle.State != CandleStates.Finished:
return
open_price = float(candle.OpenPrice)
close = float(candle.ClosePrice)
ha_close = (open_price + float(candle.HighPrice) + float(candle.LowPrice) + close) / 4.0
if self._prev_ha_open is not None and self._prev_ha_close is not None:
ha_open = (self._prev_ha_open + self._prev_ha_close) / 2.0
else:
ha_open = (open_price + close) / 2.0
self._prev_ha_open = ha_open
self._prev_ha_close = ha_close
fast = float(to_decimal(process_float(self._fast_ema, ha_close, candle.ServerTime, True)))
slow = float(to_decimal(process_float(self._slow_ema, ha_close, candle.ServerTime, True)))
if not self._fast_ema.IsFormed or not self._slow_ema.IsFormed:
return
if not self.IsFormedAndOnlineAndAllowTrading():
return
if ha_close > ha_open and fast > slow and self.Position <= 0:
self.BuyMarket(self.Volume + abs(self.Position))
elif ha_close < ha_open and fast < slow and self.Position >= 0:
self.SellMarket(self.Volume + abs(self.Position))
def CreateClone(self):
return javo_v1_strategy()