HelloSmart策略
该策略实现单向网格交易。市场每向上次入场价反向移动设定的跳数,就会加仓一次。当累计仓位达到阈值时,下一笔订单的手数按乘数放大。当总盈亏达到设定的盈利或亏损限额时,平掉所有仓位。
参数
- Trade Direction – 1 仅做多,2 仅做空。
- Step – 加仓前价格需反向运动的跳数。
- Initial Lot – 第一笔订单的基础手数。
- Threshold Volume – 触发手数放大的累计仓位。
- Maximum Lot – 单笔订单允许的最大手数。
- Profit Target – 达到该盈利金额后全部平仓。
- Loss Limit – 达到该亏损金额后全部平仓。
- Lot Multiplier – 累计仓位达到阈值后应用到下一笔订单的乘数。
- Candle Type – 用于计算价格运动的K线类型。
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>
/// Grid strategy that opens sequential orders in a single direction.
/// Closes all positions on reaching profit or loss limits.
/// </summary>
public class HelloSmartStrategy : Strategy
{
public enum TradeModes
{
Buy,
Sell
}
private readonly StrategyParam<TradeModes> _tradeMode;
private readonly StrategyParam<decimal> _stepTicks;
private readonly StrategyParam<decimal> _profitTarget;
private readonly StrategyParam<decimal> _lossLimit;
private readonly StrategyParam<DataType> _candleType;
private decimal _lastPrice;
public TradeModes Mode { get => _tradeMode.Value; set => _tradeMode.Value = value; }
public decimal StepTicks { get => _stepTicks.Value; set => _stepTicks.Value = value; }
public decimal ProfitTarget { get => _profitTarget.Value; set => _profitTarget.Value = value; }
public decimal LossLimit { get => _lossLimit.Value; set => _lossLimit.Value = value; }
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public HelloSmartStrategy()
{
_tradeMode = Param(nameof(Mode), TradeModes.Sell)
.SetDisplay("Trade Direction", "Buy or Sell direction", "General");
_stepTicks = Param(nameof(StepTicks), 300m)
.SetGreaterThanZero()
.SetDisplay("Step", "Price movement to add position", "Risk");
_profitTarget = Param(nameof(ProfitTarget), 60m)
.SetDisplay("Profit Target", "Close all positions on this profit", "Risk");
_lossLimit = Param(nameof(LossLimit), 5100m)
.SetDisplay("Loss Limit", "Close all positions on this loss", "Risk");
_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();
_lastPrice = 0m;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_lastPrice = 0m;
var subscription = SubscribeCandles(CandleType);
subscription.Bind(ProcessCandle).Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle)
{
if (candle.State != CandleStates.Finished)
return;
if (!IsFormedAndOnlineAndAllowTrading())
return;
var price = candle.ClosePrice;
var stepPrice = StepTicks * 0.01m;
// Check PnL limits first
if (Position != 0 && (PnL > ProfitTarget || PnL < -LossLimit))
{
if (Position > 0)
SellMarket();
else
BuyMarket();
_lastPrice = price;
return;
}
if (Mode == TradeModes.Buy)
{
var needOpen = Position <= 0 || (Position > 0 && (_lastPrice - price) >= stepPrice);
if (needOpen)
{
BuyMarket();
_lastPrice = price;
}
}
else
{
var needOpen = Position >= 0 || (Position < 0 && (price - _lastPrice) >= stepPrice);
if (needOpen)
{
SellMarket();
_lastPrice = price;
}
}
}
}
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 hello_smart_strategy(Strategy):
"""
Grid strategy that opens sequential orders in a single direction.
Closes all positions on reaching profit or loss limits.
Mode 0 = Buy direction, Mode 1 = Sell direction.
"""
def __init__(self):
super(hello_smart_strategy, self).__init__()
self._trade_mode = self.Param("Mode", 1) \
.SetDisplay("Trade Direction", "0=Buy, 1=Sell", "General")
self._step_ticks = self.Param("StepTicks", 300.0) \
.SetDisplay("Step", "Price movement to add position", "Risk")
self._profit_target = self.Param("ProfitTarget", 60.0) \
.SetDisplay("Profit Target", "Close all positions on this profit", "Risk")
self._loss_limit = self.Param("LossLimit", 5100.0) \
.SetDisplay("Loss Limit", "Close all positions on this loss", "Risk")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(4))) \
.SetDisplay("Candle Type", "Type of candles", "General")
self._last_price = 0.0
@property
def candle_type(self):
return self._candle_type.Value
def OnReseted(self):
super(hello_smart_strategy, self).OnReseted()
self._last_price = 0.0
def OnStarted2(self, time):
super(hello_smart_strategy, self).OnStarted2(time)
subscription = self.SubscribeCandles(self.candle_type)
subscription.Bind(self._process_candle).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawOwnTrades(area)
def _process_candle(self, candle):
if candle.State != CandleStates.Finished:
return
price = float(candle.ClosePrice)
step_price = self._step_ticks.Value * 0.01
if self.Position != 0:
pnl = float(self.PnL)
if pnl > self._profit_target.Value or pnl < -self._loss_limit.Value:
if self.Position > 0:
self.SellMarket()
else:
self.BuyMarket()
self._last_price = price
return
if self._trade_mode.Value == 0:
need_open = self.Position <= 0 or (self.Position > 0 and (self._last_price - price) >= step_price)
if need_open:
self.BuyMarket()
self._last_price = price
else:
need_open = self.Position >= 0 or (self.Position < 0 and (price - self._last_price) >= step_price)
if need_open:
self.SellMarket()
self._last_price = price
def CreateClone(self):
return hello_smart_strategy()