Candle Trader策略
概述
Candle Trader策略 分析最近4根K线的开收价方向,寻找短期的逆转机会。该策略在单一品种上运行,使用市价委托,并为每笔交易设置预先确定的止盈和止损。
策略逻辑
- 做多直接入场 – 最近一根为阳线,前两根为阴线。
- 做多连续入场 – 最近一根阳线,前一根阴线,再前两根阳线,仅在启用 Continuation 时生效。
- 做空直接入场 – 最近一根为阴线,前两根阳线。
- 做空连续入场 – 最近一根阴线,前一根阳线,再前两根阴线,仅在启用 Continuation 时生效。
- 如果启用 Reverse Close,新信号与现有仓位相反,策略会先关闭相反仓位再入新仓。
- 所有订单均用预设的止盈、止损(价格步长)进行保护。
参数
| 名称 | 说明 |
|---|---|
Volume |
单笔交易的量。 |
TakeProfitTicks |
止盈距离(价格步长)。 |
StopLossTicks |
止损距离(价格步长)。 |
Continuation |
是否启用连续型入场。 |
ReverseClose |
新信号出现时是否先关止相反仓位。 |
CandleType |
分析所用的点价类型。 |
注意事项
- 策略仅分析已完成的K线。
- 每次发出市价委托前会取消所有未结委托。
- 通过
StartProtection设置止盈和止损。 Volume参数可用于优化。
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>
/// Strategy based on candle direction patterns.
/// Opens long or short positions depending on the directions of the last four candles.
/// </summary>
public class CandleTraderStrategy : Strategy
{
private readonly StrategyParam<decimal> _volume;
private readonly StrategyParam<decimal> _takeProfitTicks;
private readonly StrategyParam<decimal> _stopLossTicks;
private readonly StrategyParam<bool> _continuation;
private readonly StrategyParam<bool> _reverseClose;
private readonly StrategyParam<DataType> _candleType;
private int _bar1Dir;
private int _bar2Dir;
private int _bar3Dir;
private int _bar4Dir;
/// <summary>
/// Order volume.
/// </summary>
public decimal TradeVolume
{
get => _volume.Value;
set => _volume.Value = value;
}
/// <summary>
/// Take profit in price steps.
/// </summary>
public decimal TakeProfitTicks
{
get => _takeProfitTicks.Value;
set => _takeProfitTicks.Value = value;
}
/// <summary>
/// Stop loss in price steps.
/// </summary>
public decimal StopLossTicks
{
get => _stopLossTicks.Value;
set => _stopLossTicks.Value = value;
}
/// <summary>
/// Enable continuation pattern.
/// </summary>
public bool Continuation
{
get => _continuation.Value;
set => _continuation.Value = value;
}
/// <summary>
/// Close opposite position before opening a new one.
/// </summary>
public bool ReverseClose
{
get => _reverseClose.Value;
set => _reverseClose.Value = value;
}
/// <summary>
/// Candle type.
/// </summary>
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
/// <summary>
/// Constructor.
/// </summary>
public CandleTraderStrategy()
{
_volume = Param(nameof(TradeVolume), 0.1m)
.SetGreaterThanZero()
.SetDisplay("Volume", "Order volume", "General");
_takeProfitTicks = Param(nameof(TakeProfitTicks), 500m)
.SetGreaterThanZero()
.SetDisplay("Take Profit Ticks", "Take profit in price steps", "Risk Management");
_stopLossTicks = Param(nameof(StopLossTicks), 50m)
.SetGreaterThanZero()
.SetDisplay("Stop Loss Ticks", "Stop loss in price steps", "Risk Management");
_continuation = Param(nameof(Continuation), true)
.SetDisplay("Use Continuation", "Allow continuation pattern", "Trading Logic");
_reverseClose = Param(nameof(ReverseClose), true)
.SetDisplay("Reverse Close", "Close opposite position on signal", "Trading Logic");
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).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();
_bar1Dir = _bar2Dir = _bar3Dir = _bar4Dir = 0;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(ProcessCandle)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle)
{
// Process only finished candles
if (candle.State != CandleStates.Finished)
return;
// Shift stored directions
_bar4Dir = _bar3Dir;
_bar3Dir = _bar2Dir;
_bar2Dir = _bar1Dir;
// Determine direction of current candle
_bar1Dir = candle.ClosePrice > candle.OpenPrice ? 1 : candle.ClosePrice < candle.OpenPrice ? -1 : 0;
// Ensure sufficient history
if (_bar4Dir == 0)
return;
var buyDirect = _bar1Dir == 1 && _bar2Dir == -1 && _bar3Dir == -1;
var buyCont = _bar1Dir == 1 && _bar2Dir == -1 && _bar3Dir == 1 && _bar4Dir == 1 && Continuation;
var sellDirect = _bar1Dir == -1 && _bar2Dir == 1 && _bar3Dir == 1;
var sellCont = _bar1Dir == -1 && _bar2Dir == 1 && _bar3Dir == -1 && _bar4Dir == -1 && Continuation;
if ((buyDirect || buyCont) && Position <= 0)
{
if (ReverseClose && Position < 0) BuyMarket();
BuyMarket();
}
else if ((sellDirect || sellCont) && Position >= 0)
{
if (ReverseClose && Position > 0) SellMarket();
SellMarket();
}
}
}
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.Strategies import Strategy
class candle_trader_strategy(Strategy):
"""
Strategy based on candle direction patterns.
Opens long or short positions depending on the directions of the last four candles.
"""
def __init__(self):
super(candle_trader_strategy, self).__init__()
self._trade_volume = self.Param("TradeVolume", 0.1) \
.SetDisplay("Volume", "Order volume", "General")
self._take_profit_ticks = self.Param("TakeProfitTicks", 500.0) \
.SetDisplay("Take Profit Ticks", "Take profit in price steps", "Risk Management")
self._stop_loss_ticks = self.Param("StopLossTicks", 50.0) \
.SetDisplay("Stop Loss Ticks", "Stop loss in price steps", "Risk Management")
self._continuation = self.Param("Continuation", True) \
.SetDisplay("Use Continuation", "Allow continuation pattern", "Trading Logic")
self._reverse_close = self.Param("ReverseClose", True) \
.SetDisplay("Reverse Close", "Close opposite position on signal", "Trading Logic")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(4))) \
.SetDisplay("Candle Type", "Type of candles", "General")
self._bar1_dir = 0
self._bar2_dir = 0
self._bar3_dir = 0
self._bar4_dir = 0
@property
def trade_volume(self):
return self._trade_volume.Value
@trade_volume.setter
def trade_volume(self, value):
self._trade_volume.Value = value
@property
def take_profit_ticks(self):
return self._take_profit_ticks.Value
@take_profit_ticks.setter
def take_profit_ticks(self, value):
self._take_profit_ticks.Value = value
@property
def stop_loss_ticks(self):
return self._stop_loss_ticks.Value
@stop_loss_ticks.setter
def stop_loss_ticks(self, value):
self._stop_loss_ticks.Value = value
@property
def continuation(self):
return self._continuation.Value
@continuation.setter
def continuation(self, value):
self._continuation.Value = value
@property
def reverse_close(self):
return self._reverse_close.Value
@reverse_close.setter
def reverse_close(self, value):
self._reverse_close.Value = value
@property
def candle_type(self):
return self._candle_type.Value
@candle_type.setter
def candle_type(self, value):
self._candle_type.Value = value
def OnReseted(self):
super(candle_trader_strategy, self).OnReseted()
self._bar1_dir = 0
self._bar2_dir = 0
self._bar3_dir = 0
self._bar4_dir = 0
def OnStarted2(self, time):
super(candle_trader_strategy, self).OnStarted2(time)
subscription = self.SubscribeCandles(self.candle_type)
subscription.Bind(self.on_process).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawOwnTrades(area)
def on_process(self, candle):
if candle.State != CandleStates.Finished:
return
# Shift stored directions
self._bar4_dir = self._bar3_dir
self._bar3_dir = self._bar2_dir
self._bar2_dir = self._bar1_dir
# Determine direction of current candle
if candle.ClosePrice > candle.OpenPrice:
self._bar1_dir = 1
elif candle.ClosePrice < candle.OpenPrice:
self._bar1_dir = -1
else:
self._bar1_dir = 0
# Ensure sufficient history
if self._bar4_dir == 0:
return
buy_direct = self._bar1_dir == 1 and self._bar2_dir == -1 and self._bar3_dir == -1
buy_cont = (self._bar1_dir == 1 and self._bar2_dir == -1 and self._bar3_dir == 1
and self._bar4_dir == 1 and self.continuation)
sell_direct = self._bar1_dir == -1 and self._bar2_dir == 1 and self._bar3_dir == 1
sell_cont = (self._bar1_dir == -1 and self._bar2_dir == 1 and self._bar3_dir == -1
and self._bar4_dir == -1 and self.continuation)
if (buy_direct or buy_cont) and self.Position <= 0:
if self.reverse_close and self.Position < 0:
self.BuyMarket()
self.BuyMarket()
elif (sell_direct or sell_cont) and self.Position >= 0:
if self.reverse_close and self.Position > 0:
self.SellMarket()
self.SellMarket()
def CreateClone(self):
return candle_trader_strategy()