GitHub で見る
資産パーセントロック戦略
概要
- カテゴリ: リスク管理 / アカウントレベルの自動化。
- 元のソース: MQL5 エキスパートアドバイザー "Close by Equity Percent" (#20880)。
- 目的: アカウントの資産を最後のフラット残高と比較し、資産がその残高の設定可能な倍数に成長したらすべてのオープンポジションを清算する。
- インストゥルメント: 同じポートフォリオ内の他の戦略または手動トレーダーによってすでに取引されているセキュリティ。
コアアイデア
元の MQL エキスパートアドバイザーは現在のアカウント資産をアカウント残高(ポジションがフラットになった後にのみ変化する)と比較します。資産が Balance * EquityPercentFromBalance に達するか超えると、スクリプトはすべてのオープンポジションを閉じて利益を確定します。この StockSharp ポートは、高レベル戦略 API と統合しながら同じアカウント保護ロジックを維持します。
動作方法
- 戦略が開始すると、現在のポートフォリオ価値のスナップショットを取得します。これはアカウントがフラットな間の「残高」参照として機能します。
- 戦略は設定された
Security に対して 1 分ローソク足(CandleType を通じて設定可能)を購読します。ローソク足フィードは資産チェックをトリガーするためのタイマーとしてのみ使用されます。
- 各完成したローソク足で:
- すべてのポジションがフラットな場合、残高スナップショットが最新のポートフォリオ価値に更新されます。
- 現在の資産(
Portfolio.CurrentValue)が balanceSnapshot * EquityPercentFromBalance と比較されます。
- 資産が閾値に達するか超えると、ポートフォリオ内のすべてのオープンポジションが
ClosePosition(position.Security) を通じて閉じられます。
- すべてのポジションが閉じられると残高スナップショットが再び更新され、サイクルが再起動できます。
パラメーター
| 名前 |
型 |
デフォルト |
説明 |
EquityPercentFromBalance |
decimal |
1.20 |
すべてのポジションを清算する前に達成する必要がある資産の倍数。値 1.20 は「資産が最後のフラット残高の 120% になったらすべてを閉じる」を意味します。 |
CandleType |
DataType |
1 分タイムフレームのローソク足 |
定期的な資産チェックをトリガーするためだけに使用されるデータストリーム。資産監視に好むケーデンスに合わせて調整してください。 |
実装メモ
- 各オープンポジションに対して
Strategy.ClosePosition(Security) を使用し、MQL バージョンの PositionClose ループを反映します。
- すべてのポジションがフラットになった後にのみ残高スナップショットを追跡し、MQL スクリプトが
AccountBalance に依存していた方法を再現します(ポジションが閉じられた後に更新されます)。
- 戦略はアカウントレベルです:自身はポジションを開かず、シンボルに関係なく接続されたポートフォリオ内のすべてのポジションを閉じようとします。
- 開始前に
Portfolio と Security の両方が割り当てられている必要があります。セキュリティはタイミングイベントを提供するローソク足を購読するためだけに使用されます。
使用ガイドライン
- 保護したいポートフォリオに戦略を添付し、タイマーとして使用したい
Security のローソク足ストリーム(例:高流動性インストゥルメント)を設定する。
- リスクプランに合った利益確定の倍数に
EquityPercentFromBalance を調整する。
- 戦略を開始する。資産が最後のフラット残高の指定された倍数に達するたびに、ポートフォリオ内のすべてのオープンポジションが自動的に閉じられます。
- 清算後、残高スナップショットが更新されるため、次の利益サイクルは別のクローズアウトをトリガーする前に資産が設定されたパーセンテージだけ成長するのを再び待ちます。
実践的な例
- 初期残高スナップショット = 10,000 USD。
EquityPercentFromBalance = 1.2 → 目標資産 = 12,000 USD。
- オープンポジションが価値を上げ、資産が 12,050 USD に達する。
- 戦略はすべてのオープンポジションを閉じます;ポートフォリオがフラットになると残高スナップショットが更新されます(例:12,000 USD に)。
- 次のサイクルは再び行動する前に資産が 12,000 * 1.2 = 14,400 USD を超えるのを待ちます。
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>
/// Equity percent lock strategy (simplified).
/// Trades using momentum and closes when profit target hit.
/// </summary>
public class EquityPercentLockStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _momentumLength;
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
public int MomentumLength
{
get => _momentumLength.Value;
set => _momentumLength.Value = value;
}
public EquityPercentLockStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
.SetDisplay("Candle Type", "Candles", "General");
_momentumLength = Param(nameof(MomentumLength), 10)
.SetGreaterThanZero()
.SetDisplay("Momentum Length", "Momentum period", "Indicators");
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
var momentum = new Momentum { Length = MomentumLength };
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(momentum, (ICandleMessage candle, decimal momValue) =>
{
if (candle.State != CandleStates.Finished)
return;
if (!IsFormedAndOnlineAndAllowTrading())
return;
if (momValue > 0 && Position <= 0)
{
BuyMarket();
}
else if (momValue < 0 && Position >= 0)
{
SellMarket();
}
})
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawOwnTrades(area);
}
}
}
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.Indicators import Momentum
from StockSharp.Algo.Strategies import Strategy
class equity_percent_lock_strategy(Strategy):
def __init__(self):
super(equity_percent_lock_strategy, self).__init__()
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(4))) \
.SetDisplay("Candle Type", "Candles", "General")
self._momentum_length = self.Param("MomentumLength", 10) \
.SetDisplay("Momentum Length", "Momentum period", "Indicators")
@property
def CandleType(self):
return self._candle_type.Value
@property
def MomentumLength(self):
return self._momentum_length.Value
def OnStarted2(self, time):
super(equity_percent_lock_strategy, self).OnStarted2(time)
momentum = Momentum()
momentum.Length = self.MomentumLength
subscription = self.SubscribeCandles(self.CandleType)
subscription.Bind(momentum, self._on_process).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawOwnTrades(area)
def _on_process(self, candle, mom_value):
if candle.State != CandleStates.Finished:
return
mv = float(mom_value)
if mv > 0 and self.Position <= 0:
self.BuyMarket()
elif mv < 0 and self.Position >= 0:
self.SellMarket()
def CreateClone(self):
return equity_percent_lock_strategy()