Hulk Grid Algorithm V2戦略
ユーザー定義の中間価格を中心に10段階の指値買い注文を並べるグリッド取引戦略です。注文サイズは中間レベルに近づくほど大きくなります。価格が最下位グリッド以下のストップロスに達するか、上位グリッド以上のテイクプロフィットに達した場合、全ポジションを決済し残りの注文をキャンセルします。
詳細
- エントリー条件: 最低レベルから最高レベルまで10本の指値買い注文のグリッド。
- ロング/ショート: ロングのみ。
- エグジット条件: 最下位グリッド以下のストップロスまたは上位グリッド以上のテイクプロフィット。
- ストップ: パーセンテージベースのストップロスとテイクプロフィット。
- デフォルト値:
MidPrice= 0StopLossPercent= 2.0TakeProfitPercent= 2.0GridStep= 200Lot= 50CandleType= TimeSpan.FromMinutes(1)
- フィルター:
- カテゴリ: Grid
- 方向: Long
- インジケーター: なし
- ストップ: はい
- 複雑さ: 基本
- 時間軸: 任意
- 季節性: いいえ
- ニューラルネットワーク: いいえ
- ダイバージェンス: いいえ
- リスクレベル: 中
using System;
using System.Collections.Generic;
using Ecng.Common;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// Hulk Grid Algorithm V2 strategy.
/// Places ten buy limit orders at MidPrice +/- 1..5 GridStep (MidPrice 0 means the current close). An order k steps from the mid
/// has volume Lot * (6 - k), so orders closer to the mid are larger. When price touches StopLossPercent below the lowest level or
/// TakeProfitPercent above the highest level, the position is closed and the remaining orders are cancelled. With MidPrice 0
/// a new grid is then built around the current close.
/// </summary>
public class HulkGridAlgorithmV2Strategy : Strategy
{
private const int _levelsPerSide = 5;
private readonly StrategyParam<decimal> _midPrice;
private readonly StrategyParam<decimal> _stopLossPercent;
private readonly StrategyParam<decimal> _takeProfitPercent;
private readonly StrategyParam<decimal> _gridStep;
private readonly StrategyParam<decimal> _lot;
private readonly StrategyParam<DataType> _candleType;
private bool _gridActive;
private bool _gridCompleted;
private decimal _stopPrice;
private decimal _takePrice;
/// <summary>
/// Grid mid price, 0 uses the current close.
/// </summary>
public decimal MidPrice
{
get => _midPrice.Value;
set => _midPrice.Value = value;
}
/// <summary>
/// Stop loss in percent below the lowest grid level.
/// </summary>
public decimal StopLossPercent
{
get => _stopLossPercent.Value;
set => _stopLossPercent.Value = value;
}
/// <summary>
/// Take profit in percent above the highest grid level.
/// </summary>
public decimal TakeProfitPercent
{
get => _takeProfitPercent.Value;
set => _takeProfitPercent.Value = value;
}
/// <summary>
/// Price distance between grid levels.
/// </summary>
public decimal GridStep
{
get => _gridStep.Value;
set => _gridStep.Value = value;
}
/// <summary>
/// Base order volume.
/// </summary>
public decimal Lot
{
get => _lot.Value;
set => _lot.Value = value;
}
/// <summary>
/// Candle type.
/// </summary>
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
/// <summary>
/// Constructor.
/// </summary>
public HulkGridAlgorithmV2Strategy()
{
_midPrice = Param(nameof(MidPrice), 0m)
.SetNotNegative()
.SetDisplay("Mid Price", "Grid mid price, 0 uses the current close", "Grid");
_stopLossPercent = Param(nameof(StopLossPercent), 2.0m)
.SetNotNegative()
.SetDisplay("Stop Loss %", "Stop loss in percent below the lowest grid level", "Risk");
_takeProfitPercent = Param(nameof(TakeProfitPercent), 2.0m)
.SetNotNegative()
.SetDisplay("Take Profit %", "Take profit in percent above the highest grid level", "Risk");
_gridStep = Param(nameof(GridStep), 200m)
.SetGreaterThanZero()
.SetDisplay("Grid Step", "Price distance between grid levels", "Grid");
_lot = Param(nameof(Lot), 50m)
.SetGreaterThanZero()
.SetDisplay("Lot", "Base order volume", "Grid");
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(1).TimeFrame())
.SetDisplay("Candle Type", "Type of candles to use", "General");
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
ResetState();
}
private void ResetState()
{
_gridActive = false;
_gridCompleted = false;
_stopPrice = 0m;
_takePrice = 0m;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
ResetState();
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;
if (_gridActive)
{
if (candle.LowPrice <= _stopPrice || candle.HighPrice >= _takePrice)
{
CancelActiveOrders();
if (Position > 0)
SellMarket(Position);
_gridActive = false;
_gridCompleted = MidPrice > 0;
}
return;
}
if (_gridCompleted || Position != 0)
return;
PlaceGrid(MidPrice > 0 ? MidPrice : candle.ClosePrice);
}
private void PlaceGrid(decimal mid)
{
var step = Security.PriceStep ?? 1m;
if (step <= 0)
step = 1m;
var lowest = decimal.MaxValue;
var highest = decimal.MinValue;
for (var k = -_levelsPerSide; k <= _levelsPerSide; k++)
{
if (k == 0)
continue;
var price = Math.Round((mid + k * GridStep) / step) * step;
if (price <= 0)
continue;
BuyLimit(price, Lot * (_levelsPerSide + 1 - Math.Abs(k)));
lowest = Math.Min(lowest, price);
highest = Math.Max(highest, price);
}
if (lowest == decimal.MaxValue)
return;
_stopPrice = lowest * (1m - StopLossPercent / 100m);
_takePrice = highest * (1m + TakeProfitPercent / 100m);
_gridActive = true;
}
}
import clr
clr.AddReference("StockSharp.Messages")
clr.AddReference("StockSharp.Algo")
clr.AddReference("StockSharp.Algo.Strategies")
from System import TimeSpan, Decimal
from StockSharp.Messages import DataType, CandleStates
from StockSharp.Algo.Strategies import Strategy
LEVELS_PER_SIDE = 5
class hulk_grid_algorithm_v2_strategy(Strategy):
"""
Hulk Grid Algorithm V2 strategy.
Places ten buy limit orders at MidPrice +/- 1..5 GridStep (MidPrice 0 means the current close). An order k steps from the mid
has volume Lot * (6 - k), so orders closer to the mid are larger. When price touches StopLossPercent below the lowest level or
TakeProfitPercent above the highest level, the position is closed and the remaining orders are cancelled. With MidPrice 0
a new grid is then built around the current close.
"""
def __init__(self):
super(hulk_grid_algorithm_v2_strategy, self).__init__()
self._mid_price = self.Param("MidPrice", 0.0).SetNotNegative().SetDisplay("Mid Price", "Grid mid price, 0 uses the current close", "Grid")
self._stop_loss_percent = self.Param("StopLossPercent", 2.0).SetNotNegative().SetDisplay("Stop Loss %", "Stop loss in percent below the lowest grid level", "Risk")
self._take_profit_percent = self.Param("TakeProfitPercent", 2.0).SetNotNegative().SetDisplay("Take Profit %", "Take profit in percent above the highest grid level", "Risk")
self._grid_step = self.Param("GridStep", 200.0).SetGreaterThanZero().SetDisplay("Grid Step", "Price distance between grid levels", "Grid")
self._lot = self.Param("Lot", 50.0).SetGreaterThanZero().SetDisplay("Lot", "Base order volume", "Grid")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(1))).SetDisplay("Candle Type", "Type of candles to use", "General")
self._reset_state()
@property
def candle_type(self):
return self._candle_type.Value
def _reset_state(self):
self._grid_active = False
self._grid_completed = False
self._stop_price = 0.0
self._take_price = 0.0
def OnReseted(self):
super(hulk_grid_algorithm_v2_strategy, self).OnReseted()
self._reset_state()
def OnStarted2(self, time):
super(hulk_grid_algorithm_v2_strategy, self).OnStarted2(time)
self._reset_state()
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
if not self.IsFormedAndOnlineAndAllowTrading():
return
mid_param = float(self._mid_price.Value)
if self._grid_active:
if float(candle.LowPrice) <= self._stop_price or float(candle.HighPrice) >= self._take_price:
self.CancelActiveOrders()
if self.Position > 0:
self.SellMarket(self.Position)
self._grid_active = False
self._grid_completed = mid_param > 0
return
if self._grid_completed or self.Position != 0:
return
self._place_grid(mid_param if mid_param > 0 else float(candle.ClosePrice))
def _place_grid(self, mid):
step = 1.0
if self.Security.PriceStep is not None and float(self.Security.PriceStep) > 0:
step = float(self.Security.PriceStep)
grid_step = float(self._grid_step.Value)
lot = float(self._lot.Value)
lowest = None
highest = None
for k in range(-LEVELS_PER_SIDE, LEVELS_PER_SIDE + 1):
if k == 0:
continue
price = round((mid + k * grid_step) / step) * step
if price <= 0:
continue
self.BuyLimit(Decimal(price), Decimal(lot * (LEVELS_PER_SIDE + 1 - abs(k))))
lowest = price if lowest is None else min(lowest, price)
highest = price if highest is None else max(highest, price)
if lowest is None:
return
self._stop_price = lowest * (1.0 - float(self._stop_loss_percent.Value) / 100.0)
self._take_price = highest * (1.0 + float(self._take_profit_percent.Value) / 100.0)
self._grid_active = True
def CreateClone(self):
return hulk_grid_algorithm_v2_strategy()