CSPA 1.43 策略
该策略是 CSPA-1_43 MQL 智能交易系统的改写版本。它通过相对强弱指数(RSI)衡量货币对的强弱。当货币对表现出足够的强势或弱势时,策略按趋势方向开仓,并在动能减弱时平仓。
逻辑
- 订阅所选证券的K线。
- 计算每根完结K线的RSI数值。
- 当RSI上穿上阈值时做多。
- 当RSI下破下阈值时做空。
- 当RSI回到中性区域时平仓。
参数
| 名称 | 描述 | 默认值 |
|---|---|---|
StrengthPeriod |
RSI 指标的周期。 | 14 |
Threshold |
与RSI中性值50的偏差,用于生成信号。 | 10 |
CandleType |
K线的时间框架。 | 1 小时 |
说明
- 策略使用高层 API 并自动绑定指标。
- 使用市价单 (
BuyMarket和SellMarket) 执行交易。 - 仅处理已完成的K线。
using System;
using System.Collections.Generic;
using Ecng.Common;
using Ecng.Serialization;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// Simplified currency strength strategy based on RSI.
/// </summary>
public class Cspa143Strategy : Strategy
{
private readonly StrategyParam<int> _strengthPeriod;
private readonly StrategyParam<decimal> _threshold;
private readonly StrategyParam<int> _cooldownBars;
private readonly StrategyParam<DataType> _candleType;
private decimal _previousRsi;
private bool _isInitialized;
private int _barsSinceTrade;
/// <summary>
/// RSI period.
/// </summary>
public int StrengthPeriod
{
get => _strengthPeriod.Value;
set => _strengthPeriod.Value = value;
}
/// <summary>
/// RSI distance from 50.
/// </summary>
public decimal Threshold
{
get => _threshold.Value;
set => _threshold.Value = value;
}
/// <summary>
/// Bars to wait after a completed trade.
/// </summary>
public int CooldownBars
{
get => _cooldownBars.Value;
set => _cooldownBars.Value = value;
}
/// <summary>
/// Candle type.
/// </summary>
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
/// <summary>
/// Initializes a new instance of the strategy.
/// </summary>
public Cspa143Strategy()
{
_strengthPeriod = Param(nameof(StrengthPeriod), 14)
.SetDisplay("Strength Period", "RSI period", "Parameters");
_threshold = Param(nameof(Threshold), 18m)
.SetDisplay("Threshold", "RSI distance from 50", "Parameters")
.SetGreaterThanZero();
_cooldownBars = Param(nameof(CooldownBars), 2)
.SetDisplay("Cooldown Bars", "Bars to wait after a completed trade", "Parameters");
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(1).TimeFrame())
.SetDisplay("Candle Type", "Type of candles", "General");
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_previousRsi = 0m;
_isInitialized = false;
_barsSinceTrade = CooldownBars;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
var rsi = new RelativeStrengthIndex { Length = StrengthPeriod };
var subscription = SubscribeCandles(CandleType);
subscription.Bind(rsi, ProcessCandle).Start();
}
private void ProcessCandle(ICandleMessage candle, decimal rsi)
{
if (candle.State != CandleStates.Finished)
return;
if (!IsFormedAndOnlineAndAllowTrading())
return;
if (_barsSinceTrade < CooldownBars)
_barsSinceTrade++;
var upper = 50m + Threshold;
var lower = 50m - Threshold;
if (!_isInitialized)
{
_previousRsi = rsi;
_isInitialized = true;
return;
}
var longEntry = _previousRsi <= upper && rsi > upper;
var shortEntry = _previousRsi >= lower && rsi < lower;
var longExit = Position > 0 && _previousRsi >= 55m && rsi < 55m;
var shortExit = Position < 0 && _previousRsi <= 45m && rsi > 45m;
if (longExit)
{
SellMarket(Position);
_barsSinceTrade = 0;
}
else if (shortExit)
{
BuyMarket(-Position);
_barsSinceTrade = 0;
}
else if (_barsSinceTrade >= CooldownBars)
{
if (longEntry && Position <= 0)
{
BuyMarket(Volume + Math.Abs(Position));
_barsSinceTrade = 0;
}
else if (shortEntry && Position >= 0)
{
SellMarket(Volume + Math.Abs(Position));
_barsSinceTrade = 0;
}
}
_previousRsi = rsi;
}
}
import clr
clr.AddReference("StockSharp.Messages")
clr.AddReference("StockSharp.Algo")
clr.AddReference("StockSharp.Algo.Indicators")
clr.AddReference("StockSharp.Algo.Strategies")
from System import TimeSpan, Math
from StockSharp.Messages import DataType, CandleStates
from StockSharp.Algo.Indicators import RelativeStrengthIndex
from StockSharp.Algo.Strategies import Strategy
class cspa143_strategy(Strategy):
def __init__(self):
super(cspa143_strategy, self).__init__()
self._strength_period = self.Param("StrengthPeriod", 14) \
.SetDisplay("Strength Period", "RSI period", "Parameters")
self._threshold = self.Param("Threshold", 18.0) \
.SetDisplay("Threshold", "RSI distance from 50", "Parameters")
self._cooldown_bars = self.Param("CooldownBars", 2) \
.SetDisplay("Cooldown Bars", "Bars to wait after a completed trade", "Parameters")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(1))) \
.SetDisplay("Candle Type", "Type of candles", "General")
self._previous_rsi = 0.0
self._is_initialized = False
self._bars_since_trade = 0
@property
def StrengthPeriod(self):
return self._strength_period.Value
@StrengthPeriod.setter
def StrengthPeriod(self, value):
self._strength_period.Value = value
@property
def Threshold(self):
return self._threshold.Value
@Threshold.setter
def Threshold(self, value):
self._threshold.Value = value
@property
def CooldownBars(self):
return self._cooldown_bars.Value
@CooldownBars.setter
def CooldownBars(self, value):
self._cooldown_bars.Value = value
@property
def CandleType(self):
return self._candle_type.Value
@CandleType.setter
def CandleType(self, value):
self._candle_type.Value = value
def OnStarted2(self, time):
super(cspa143_strategy, self).OnStarted2(time)
rsi = RelativeStrengthIndex()
rsi.Length = self.StrengthPeriod
subscription = self.SubscribeCandles(self.CandleType)
subscription.Bind(rsi, self.ProcessCandle).Start()
def ProcessCandle(self, candle, rsi_value):
if candle.State != CandleStates.Finished:
return
rsi = float(rsi_value)
if self._bars_since_trade < self.CooldownBars:
self._bars_since_trade += 1
upper = 50.0 + float(self.Threshold)
lower = 50.0 - float(self.Threshold)
if not self._is_initialized:
self._previous_rsi = rsi
self._is_initialized = True
return
long_entry = self._previous_rsi <= upper and rsi > upper
short_entry = self._previous_rsi >= lower and rsi < lower
long_exit = self.Position > 0 and self._previous_rsi >= 55.0 and rsi < 55.0
short_exit = self.Position < 0 and self._previous_rsi <= 45.0 and rsi > 45.0
if long_exit:
self.SellMarket(self.Position)
self._bars_since_trade = 0
elif short_exit:
self.BuyMarket(-self.Position)
self._bars_since_trade = 0
elif self._bars_since_trade >= self.CooldownBars:
pos = self.Position
if long_entry and pos <= 0:
self.BuyMarket(self.Volume + abs(pos))
self._bars_since_trade = 0
elif short_entry and pos >= 0:
self.SellMarket(self.Volume + abs(pos))
self._bars_since_trade = 0
self._previous_rsi = rsi
def OnReseted(self):
super(cspa143_strategy, self).OnReseted()
self._previous_rsi = 0.0
self._is_initialized = False
self._bars_since_trade = self.CooldownBars
def CreateClone(self):
return cspa143_strategy()