個々の投資目標に合わせた自分だけの取引戦略を確定したら、大変な作業は終わったと思われるかもしれません。しかし、経験豊富なトレーダーが教えてくれるように、これは真実とは程遠いものです。
暗号化取引ボットは自動化されていますが、自動化されていないため、特にボラティリティの高い時期には定期的な監視が必要です。トレーダーとしては、利益を最適化するため、あるいは不況時の損失を抑えるために、自分の取引戦略を特定の市場体制に合わせたいものです。そこで、考えられる市場状況の範囲に基づいて自分の戦略を調整するためのアイデアをいくつかまとめてみました。
大きなドローダウンを減らすためのアイデア
一取引あたりのリスクを固定した注文を管理するために、トリプル・バリア方式を使用する。トリプルバリアは、ストップロスを入れて損失を限定する一方、一定時間後にポジションをクローズして、相場の方向転換を防ぐものです。実は、私たちは、情報提供のために書いた
トレードの終了方法に関するガイドつまり、ポジションを閉じることです。を使用したシンプルな取引戦略にすべてをまとめました。 トラリピコードエディタ.すべてのPythonコードをステップ・バイ・ステップで解説しています。
トレーリング・ストップ・ロスを使用して勝者を走らせる
トレイリングストップロスを使用すると、トレンドフォロー戦略で最大損失を制限しながらも、勝者を走らせ続けることができます。より詳しい情報は、Tralityのドキュメントで見ることができます。 トレーリング注文タイプ.
""" Stop price is the inital price of the stop order
For a sell the stop should be placed below the current market price
When the price moves up by trailing_precent the stop is moved
"""
pos = query_open_position_by_symbol(symbol=data.symbol, include_dust=False)
if pos is not None:
stoploss_amount = -pos.exposure # negative sign to sell position
stop_price = data.close[-1]*0.975
state.sl = order_trailing_iftouched_amount(symbol=data.symbol,
amount=stoploss_amount,
trailing_percent=0.025,
stop_price=stop_price)
以下は、1h EMAクロスオーバー戦略のバックテスト結果で、それぞれ10期、50期、1dスーパートレンドの場合です。高速EMAが低速EMAを上回ったらポジションを建て、高速EMAが低速EMAを下回ったら決済しています。上昇相場であっても、このストラテジーのパフォーマンスは低い。
以下は同じ戦略ですが、ポジションの出口は市場より2.5%下のトレイリングストップロスを使用し、2.5%刻みでポジションを終了しています。利益と最大ドローダウンの両方において、パフォーマンスが大幅に向上しています。
連続負けトレードの修正
連勝と連敗の両方があるストラテジーを改善できる方法として、最近のストップロスの回数が増えたら取引しないようにクールダウンを追加することを検討することが挙げられます。ストラテジーは、トレンドやレンジといった特定の相場状況をターゲットにすることが多い。ストラテジーがうまく機能しているときは、「金以上」のサインであり、高い勝率になる可能性が高いです。トレンドフォローのストラテジーは、強気相場では80%の勝率だが、弱気相場では20%しか勝てないかもしれない。最近の勝率を監視することで、市場環境がボットにとって最適ではなく、市場環境がより有望に見えるまで待つのが最善かもしれないと推論することができます。適切な市況にあるときの期待勝率が80%のボットでは、2回続けて負ける確率は4%しかありません。この情報は、次のシグナルをどのように取引するかを決定するのに有効です。
################################################################################
# compute time as a datetime and store
################################################################################
now = datetime.fromtimestamp(data.times[-1] / 1000.0, pytz.UTC)
if state.cooldown[data.symbol] is None:
state.cooldown[data.symbol] = now
################################################################################
# set a cooldown timer if the stop loss is filled
################################################################################
if sl_order is not None:
sl_order.refresh() # make sure the order is up to date
if sl_order.is_filled():
# wait before placing more orders if the strategy was stopped out
state.cooldown[data.symbol] = now + timedelta(hours=COOLDOWN_HOURS)
log(f"stop loss hit waiting {COOLDOWN_HOURS} hours before trading again", severity=3)
################################################################################
# check before trading if the strategy is in cooldown
################################################################################
if now >= state.cooldown[data.symbol]:
... # strategy code here
if should_trade:
order_market_value(symbol=data.symbol, value=100)
長期的なトレンドの方向性を測定するために、より長い時間枠でトレンド指標を使用する
長期トレンドは多くの小さなトレンドから構成されているため、「より大きな絵」を 理解することが戦略のパフォーマンスにとって重要である理由です。複数の時間枠の戦略は、より長期のトレンドを利用することで、大きなドローダウンを回避し、より高い勝率を達成することができます。
単純な EMA クロスオーバー戦略は、弱気相場ではリスク調整後 の取引成績が悪くなります。これは、存在しない可能性の高いトレンドを探すためである。あるいは、あったとしても、あまり長くは続かない。
###############################################################
# Multi symbol 1h moving average cross over strategy
###############################################################
SYMBOLS=["BTCUSDT", "ETHUSDT"]
def initialize(state):
pass
@schedule(interval="1h", symbol=SYMBOLS, window_size=200)
def handler_1h(state, dataMap):
for symbol, data in dataMap.items():
if data is None:
continue
ema1 = data.ema(10)
ema2 = data.ema(50)
port = query_portfolio()
pos = query_open_position_by_symbol(symbol=data.symbol, include_dust=False)
if pos is None :
if ema1[-1] > ema2[-1]:
trade_size = port.portfolio_value * Decimal(.995) / len(SYMBOLS)
trade_size = min(query_balance_free(data.quoted), trade_size)
order_market_value(symbol=data.symbol, value=trade_size)
else:
if ema1[-1] < ema2[-1]:
close_position(data.symbol)
この戦略は上昇トレンドではよく機能するが、市場が弱気になると本当に苦戦する。これは、PnLパフォーマンスと最大ドローダウンの両方で見ることができます。
長期(1d)super_trend指標を追加すると、ボットの長期弱気相場への対処能力が大幅に向上します。
###############################################################
# Multi symbol 1h moving average cross over strategy
# With 1d super trend indicator
###############################################################
SYMBOLS=["BTCUSDT", "ETHUSDT"]
def initialize(state):
state.st_trend = {}
@schedule(interval="1d", symbol=SYMBOLS, window_size=200)
def handler_1d(state, dataMap):
for symbol, data in dataMap.items():
if data is None:
continue
st = data.super_trend(24, 3.0)
state.st_trend[symbol] = st["trend"][-1]
@schedule(interval="1h", symbol=SYMBOLS, window_size=200)
def handler_1h(state, dataMap):
for symbol, data in dataMap.items():
if data is None:
continue
ema1 = data.ema(10)
ema2 = data.ema(50)
port = query_portfolio()
pos = query_open_position_by_symbol(symbol=data.symbol, include_dust=False)
if state.st_trend.get(data.symbol,0) > 0 :
if pos is None :
if ema1[-1] > ema2[-1]:
trade_size = port.portfolio_value * Decimal(.995) / len(SYMBOLS)
trade_size = min(query_balance_free(data.quoted), trade_size)
order_market_value(symbol=data.symbol, value=trade_size)
else:
if ema1[-1] < ema2[-1]:
close_position(data.symbol)
else:
close_position(data.symbol)
上記のボットは、1日ハンドラ内でsuper_trendインディケータを使用し、1時間ハンドラに長期トレンドが何であるかを指示することを追加しています。バックテストでのこの効果は、長期トレンドが弱気であるときに、ドローダウンを大幅に減少させることである。PnL/drawdown で測定したシンプルな戦略のパフォーマンスは、0.1727 から 4.22 に向上しています。
リスクは市場のボラティリティに比例するように、バリュー・アット・リスク(VaR)を使ってポジションをスケールする。
ボラティリティが通常より明らかに高くなる市場の暴落時に損失が発生することが多い。価格の共分散と現在のポジションを使用して戦略のリスクを監視し、口座残高ではなく、VaRによって推定される戦略の総リスクに基づいて、戦略のリスクを制限することが有益である。
import numpy as np
##############################################################
# User configs
SYMBOLS = ["XMRUSDT", "ETHUSDT", "DOGEUSDT"]
ATR_PERIODS = 24
RISK_TARGET = 25.0 # risk target for strategy
##############################################################
def clamp(x, lo, hi):
return min(hi, max(x, lo))
'''
Compute the risk of the portfolio
'''
def compute_portfolio_risk(dataMap, plot_risk=True) :
bars_in_day = 24
# compute
for symbol, data in dataMap.items() :
bar_len_secs = (data.times[-1] - data.times[-2]) / 1000
bars_in_day = (24*60*60) / bar_len_secs
break
risk = 0
try:
# compute portfolio risk
returns, vols = [], []
positions = []
for symbol, data in dataMap.items() :
if data is None :
continue
log_returns = np.diff(np.log(data.select("close"))[1:])
returns.append(log_returns)
vols.append(data.atr(ATR_PERIODS)[-1]/float(data.close.last))
pos = query_open_position_by_symbol(symbol=data.symbol, include_dust=False)
positions.append(float(0 if pos is None else pos.position_value))
# plot position
plot_line("pos", 0.0 if pos is None else float(pos.position_value), symbol=data.symbol)
# create a covariance matrix using ATR
corr = np.corrcoef(returns)
covar = np.matmul(corr, np.diag(np.square(vols)))
# compute portfolio risk
risk = np.sqrt(np.matmul(np.matmul(np.transpose(positions), covar), positions) * bars_in_day)
if plot_risk :
for symbol, data in dataMap.items() :
plot_line("risk", risk, symbol)
except Exception as e:
log(f"error computing risk {e}", severity=3)
return risk
def initialize(state):
pass
@schedule(interval="1h", symbol=SYMBOLS, window_size = 200)
def handler(state, dataMap):
# calculate and plot portfolio risk
portfolio_risk = compute_portfolio_risk(dataMap, plot_risk=True)
for symbol, data in dataMap.items() :
#pos = query_open_position_by_symbol(symbol, include_dust=False)
pweight = float(query_position_weight(symbol=data.symbol))
if state.run == 0 :
starget = 0.5 / len(SYMBOLS)
else:
starget = pweight * (RISK_TARGET / portfolio_risk)
# check if the difference between
if abs(starget - pweight) * float(query_portfolio_value()) > 25.0:
order_market_target(symbol, starget)
ポートフォリオのリスクが高まるにつれて、ポジションを減らしていき、総リスクを範囲内に収める。
重要な関数はcompute_portfolio_riskで、翌日のポートフォリオの予想ボラティリティが得られます。
portfolio_risk = compute_portfolio_risk(dataMap, plot_risk=True)
このポートフォリオリスクを用いて、リスクが限界を超えた場合の判断を行うことができます。ボットの場合、リスクと目標リスクの比率に相対するポジションサイズを目標とします。
starget = pweight * (RISK_TARGET / portfolio_risk)
これにより、ボラティリティが低いときはポジションを増やし、ボラティリティが高いときはポジションサイズを減らすということが自然にできるようになります。
アセット・セレクション
戦略最適化プロセスのもう一つの重要な部分は、資産選択です。これは、ある市場体制と別の市場体制に向かう傾向がある資産があるため、市場体制と密接に関係しています。例えば、以下のような硬貨がそうである。 SHIB と DOGE はボラティリティが高く、歴史的に強いトレンドを持っていることがあります。のようなコインは PAXG は、ダイナミクスが大きく異なり、より高いノイズと低いボラティリティで、はるかに安定する傾向があります。 BTC と ETH は、市場の出来高が最も多く、トレンドが出やすい。
各コインには独自のダイナミクスがありますが、類似のコインもまた同様のダイナミクスを持つ傾向があります。1つのコインで利益を上げる戦略は、高い相関性を持つコインの取引でも利益を上げる可能性が高いです。多くの資産の相関関係を見ると、相関関係はクラスターにまとめられる傾向があります。特定の取引戦略は、クラスター内のすべての資産で同様の取引パフォーマンスを示す可能性があります。そして、これらのクラスターを利用して、資産のバスケットを形成することができます。
トレンドフォロー戦略など、一部の戦略は、トレンド傾向のある資産を好みます。ボリンジャーバンド戦略のような平均回帰戦略は、レンジになる傾向のある資産を好みます。戦略に応じて適切な資産を選択することが重要である。
最終的な感想
取引戦略は、道具箱の中の道具と考えることができ、それぞれ(またはそれらの組み合わせ)は、特定の市場体制から利益を得るために特別に設計されています。各市場レジームには、価格の動きの特徴を示す特徴があります。トレーダーとして、最高の結果を得るためには、自由に使えるトレーディング・ツールを活用し、適切な市場レジームと組み合わせることが極めて重要です。これは、「セット・イット・アンド・フェザー」アプローチではなく、定期的なモニタリングと、目標や現在および予想される市場の状況に基づいた微調整が必要な、継続的なプロセスなのです。