山寨币指数相关策略
该策略比较交易品种和参考指数的 EMA 趋势。当两个品种的快 EMA 均高于慢 EMA 时做多,均低于慢 EMA 时做空。可选择反向逻辑或忽略指数。
详情
- 入场条件:
- 两个品种的快 EMA 高于慢 EMA(反向逻辑时相反)。
- 多空方向:双向。
- 出场条件:
- EMA 反向交叉。
- 止损:无。
- 默认值:
FastEmaLength= 47SlowEmaLength= 50IndexFastEmaLength= 47IndexSlowEmaLength= 50SkipIndexReference= falseInverseSignal= false
- 过滤器:
- 类别:趋势跟随
- 方向:双向
- 指标:EMA
- 止损:无
- 复杂度:低
- 时间框架:任意
- 季节性:无
- 神经网络:无
- 背离:无
- 风险等级:中
using System;
using System.Linq;
using System.Collections.Generic;
using Ecng.Common;
using Ecng.Collections;
using Ecng.Serialization;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// Altcoin Index Correlation Strategy - trades when EMA trends on the symbol and reference index align.
/// </summary>
public class AltcoinIndexCorrelationStrategy : Strategy
{
private readonly StrategyParam<int> _fastEmaLen;
private readonly StrategyParam<int> _slowEmaLen;
private readonly StrategyParam<int> _indexFastEmaLen;
private readonly StrategyParam<int> _indexSlowEmaLen;
private readonly StrategyParam<bool> _skipIndex;
private readonly StrategyParam<bool> _inverseSignal;
private readonly StrategyParam<Security> _indexSecurity;
private readonly StrategyParam<DataType> _candleType;
private decimal _indexFast;
private decimal _indexSlow;
private bool _indexReady;
private decimal _prevFast;
private decimal _prevSlow;
private int _barIndex;
private int _lastTradeBar;
/// <summary>
/// Length of fast EMA for main security.
/// </summary>
public int FastEmaLength
{
get => _fastEmaLen.Value;
set => _fastEmaLen.Value = value;
}
/// <summary>
/// Length of slow EMA for main security.
/// </summary>
public int SlowEmaLength
{
get => _slowEmaLen.Value;
set => _slowEmaLen.Value = value;
}
/// <summary>
/// Length of fast EMA for reference index.
/// </summary>
public int IndexFastEmaLength
{
get => _indexFastEmaLen.Value;
set => _indexFastEmaLen.Value = value;
}
/// <summary>
/// Length of slow EMA for reference index.
/// </summary>
public int IndexSlowEmaLength
{
get => _indexSlowEmaLen.Value;
set => _indexSlowEmaLen.Value = value;
}
/// <summary>
/// Skip using reference index in calculations.
/// </summary>
public bool SkipIndexReference
{
get => _skipIndex.Value;
set => _skipIndex.Value = value;
}
/// <summary>
/// Inverse correlation logic.
/// </summary>
public bool InverseSignal
{
get => _inverseSignal.Value;
set => _inverseSignal.Value = value;
}
/// <summary>
/// Reference index security.
/// </summary>
public Security IndexSecurity
{
get => _indexSecurity.Value;
set => _indexSecurity.Value = value;
}
/// <summary>
/// Candle type used for calculations.
/// </summary>
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
/// <summary>
/// Initializes parameters.
/// </summary>
public AltcoinIndexCorrelationStrategy()
{
_fastEmaLen = Param(nameof(FastEmaLength), 7)
.SetDisplay("Fast EMA", "Fast EMA length", "EMA Settings")
.SetOptimize(5, 50, 5);
_slowEmaLen = Param(nameof(SlowEmaLength), 18)
.SetDisplay("Slow EMA", "Slow EMA length", "EMA Settings")
.SetOptimize(10, 100, 5);
_indexFastEmaLen = Param(nameof(IndexFastEmaLength), 47)
.SetDisplay("Index Fast EMA", "Fast EMA length for index", "Index Reference")
.SetOptimize(10, 100, 5);
_indexSlowEmaLen = Param(nameof(IndexSlowEmaLength), 50)
.SetDisplay("Index Slow EMA", "Slow EMA length for index", "Index Reference")
.SetOptimize(10, 100, 5);
_skipIndex = Param(nameof(SkipIndexReference), false)
.SetDisplay("Skip Index", "Ignore index correlation", "Index Reference");
_inverseSignal = Param(nameof(InverseSignal), false)
.SetDisplay("Inverse Signal", "Use inverse correlation logic", "Index Reference");
_indexSecurity = Param<Security>(nameof(IndexSecurity))
.SetDisplay("Index Security", "Reference index security", "Data");
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(5).TimeFrame())
.SetDisplay("Candle Type", "Type of candles", "General");
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
yield return (Security, CandleType);
if (IndexSecurity != null)
yield return (IndexSecurity, CandleType);
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_indexFast = 0m;
_indexSlow = 0m;
_indexReady = false;
_prevFast = 0m;
_prevSlow = 0m;
_barIndex = 0;
_lastTradeBar = 0;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
var fastEma = new ExponentialMovingAverage { Length = FastEmaLength };
var slowEma = new ExponentialMovingAverage { Length = SlowEmaLength };
var mainSub = SubscribeCandles(CandleType);
mainSub
.Bind(fastEma, slowEma, ProcessMainCandle)
.Start();
if (IndexSecurity != null)
{
var indexFastEma = new ExponentialMovingAverage { Length = IndexFastEmaLength };
var indexSlowEma = new ExponentialMovingAverage { Length = IndexSlowEmaLength };
var indexSub = SubscribeCandles(CandleType, security: IndexSecurity);
indexSub
.Bind(indexFastEma, indexSlowEma, ProcessIndexCandle)
.Start();
}
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, mainSub);
DrawIndicator(area, fastEma);
DrawIndicator(area, slowEma);
DrawOwnTrades(area);
}
}
private void ProcessIndexCandle(ICandleMessage candle, decimal fast, decimal slow)
{
if (candle.State != CandleStates.Finished)
return;
_indexFast = fast;
_indexSlow = slow;
_indexReady = true;
}
private void ProcessMainCandle(ICandleMessage candle, decimal fast, decimal slow)
{
if (candle.State != CandleStates.Finished)
return;
_barIndex++;
if (_prevFast == 0 || _prevSlow == 0)
{
_prevFast = fast;
_prevSlow = slow;
return;
}
var cooldownOk = _barIndex - _lastTradeBar > 5;
// Cross-over detection
var crossOver = _prevFast <= _prevSlow && fast > slow;
var crossUnder = _prevFast >= _prevSlow && fast < slow;
bool goLong;
bool goShort;
if (SkipIndexReference || !_indexReady)
{
goLong = crossOver;
goShort = crossUnder;
}
else
{
goLong = crossOver && _indexFast > _indexSlow;
goShort = crossUnder && _indexFast < _indexSlow;
if (InverseSignal)
{
goLong = crossOver && _indexFast < _indexSlow;
goShort = crossUnder && _indexFast > _indexSlow;
}
}
if (goLong && Position <= 0 && cooldownOk)
{
BuyMarket();
_lastTradeBar = _barIndex;
}
else if (goShort && Position >= 0 && cooldownOk)
{
SellMarket();
_lastTradeBar = _barIndex;
}
_prevFast = fast;
_prevSlow = slow;
}
}
import clr
clr.AddReference("StockSharp.Messages")
clr.AddReference("StockSharp.Algo")
clr.AddReference("StockSharp.BusinessEntities")
clr.AddReference("StockSharp.Algo.Indicators")
clr.AddReference("StockSharp.Algo.Strategies")
from System import TimeSpan
from StockSharp.Messages import CandleStates
from StockSharp.Algo.Indicators import ExponentialMovingAverage
from StockSharp.Algo.Strategies import Strategy
from StockSharp.BusinessEntities import Security
from datatype_extensions import *
class altcoin_index_correlation_strategy(Strategy):
"""
Altcoin Index Correlation Strategy - trades when EMA trends on the symbol
and reference index align.
"""
def __init__(self):
super(altcoin_index_correlation_strategy, self).__init__()
self._fast_ema_len = self.Param("FastEmaLength", 7) \
.SetDisplay("Fast EMA", "Fast EMA length", "EMA Settings")
self._slow_ema_len = self.Param("SlowEmaLength", 18) \
.SetDisplay("Slow EMA", "Slow EMA length", "EMA Settings")
self._index_fast_ema_len = self.Param("IndexFastEmaLength", 47) \
.SetDisplay("Index Fast EMA", "Fast EMA length for index", "Index Reference")
self._index_slow_ema_len = self.Param("IndexSlowEmaLength", 50) \
.SetDisplay("Index Slow EMA", "Slow EMA length for index", "Index Reference")
self._skip_index = self.Param("SkipIndexReference", False) \
.SetDisplay("Skip Index", "Ignore index correlation", "Index Reference")
self._inverse_signal = self.Param("InverseSignal", False) \
.SetDisplay("Inverse Signal", "Use inverse correlation logic", "Index Reference")
self._candle_type = self.Param("CandleType", tf(5)) \
.SetDisplay("Candle Type", "Type of candles", "General")
self._index_security_param = self.Param[Security]("IndexSecurity") \
.SetDisplay("Index Security", "Reference index security", "Data")
self._index_fast = 0.0
self._index_slow = 0.0
self._index_ready = False
self._prev_fast = 0.0
self._prev_slow = 0.0
self._bar_index = 0
self._last_trade_bar = 0
@property
def FastEmaLength(self): return self._fast_ema_len.Value
@FastEmaLength.setter
def FastEmaLength(self, v): self._fast_ema_len.Value = v
@property
def SlowEmaLength(self): return self._slow_ema_len.Value
@SlowEmaLength.setter
def SlowEmaLength(self, v): self._slow_ema_len.Value = v
@property
def IndexFastEmaLength(self): return self._index_fast_ema_len.Value
@IndexFastEmaLength.setter
def IndexFastEmaLength(self, v): self._index_fast_ema_len.Value = v
@property
def IndexSlowEmaLength(self): return self._index_slow_ema_len.Value
@IndexSlowEmaLength.setter
def IndexSlowEmaLength(self, v): self._index_slow_ema_len.Value = v
@property
def SkipIndexReference(self): return self._skip_index.Value
@SkipIndexReference.setter
def SkipIndexReference(self, v): self._skip_index.Value = v
@property
def InverseSignal(self): return self._inverse_signal.Value
@InverseSignal.setter
def InverseSignal(self, v): self._inverse_signal.Value = v
@property
def IndexSecurity(self): return self._index_security_param.Value
@IndexSecurity.setter
def IndexSecurity(self, v): self._index_security_param.Value = v
@property
def CandleType(self): return self._candle_type.Value
@CandleType.setter
def CandleType(self, v): self._candle_type.Value = v
def OnReseted(self):
super(altcoin_index_correlation_strategy, self).OnReseted()
self._index_fast = 0.0
self._index_slow = 0.0
self._index_ready = False
self._prev_fast = 0.0
self._prev_slow = 0.0
self._bar_index = 0
self._last_trade_bar = 0
def OnStarted2(self, time):
super(altcoin_index_correlation_strategy, self).OnStarted2(time)
fast_ema = ExponentialMovingAverage()
fast_ema.Length = self.FastEmaLength
slow_ema = ExponentialMovingAverage()
slow_ema.Length = self.SlowEmaLength
subscription = self.SubscribeCandles(self.CandleType)
subscription.Bind(fast_ema, slow_ema, self.ProcessMainCandle).Start()
if self.IndexSecurity is not None:
index_fast_ema = ExponentialMovingAverage()
index_fast_ema.Length = self.IndexFastEmaLength
index_slow_ema = ExponentialMovingAverage()
index_slow_ema.Length = self.IndexSlowEmaLength
index_sub = self.SubscribeCandles(self.CandleType, security=self._index_security)
index_sub.Bind(index_fast_ema, index_slow_ema, self.ProcessIndexCandle).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawIndicator(area, fast_ema)
self.DrawIndicator(area, slow_ema)
self.DrawOwnTrades(area)
def ProcessIndexCandle(self, candle, fast, slow):
if candle.State != CandleStates.Finished:
return
self._index_fast = float(fast)
self._index_slow = float(slow)
self._index_ready = True
def ProcessMainCandle(self, candle, fast, slow):
if candle.State != CandleStates.Finished:
return
fast = float(fast)
slow = float(slow)
self._bar_index += 1
if self._prev_fast == 0 or self._prev_slow == 0:
self._prev_fast = fast
self._prev_slow = slow
return
cooldown_ok = self._bar_index - self._last_trade_bar > 5
cross_over = self._prev_fast <= self._prev_slow and fast > slow
cross_under = self._prev_fast >= self._prev_slow and fast < slow
if self.SkipIndexReference or not self._index_ready:
go_long = cross_over
go_short = cross_under
else:
go_long = cross_over and self._index_fast > self._index_slow
go_short = cross_under and self._index_fast < self._index_slow
if self.InverseSignal:
go_long = cross_over and self._index_fast < self._index_slow
go_short = cross_under and self._index_fast > self._index_slow
if go_long and self.Position <= 0 and cooldown_ok:
self.BuyMarket()
self._last_trade_bar = self._bar_index
elif go_short and self.Position >= 0 and cooldown_ok:
self.SellMarket()
self._last_trade_bar = self._bar_index
self._prev_fast = fast
self._prev_slow = slow
def CreateClone(self):
return altcoin_index_correlation_strategy()