トレードの終了方法

  • URLをコピーしました!

トレードの終了方法について

ALEXANDER KAHL

2020年11月26日9 読む

目次

目次

アルゴリズム取引では、取引の正しいエントリーシグナルとエグジットシグナルを見つけることに大きな重点を置いています。特にテクニカル分析の分野では、売買シグナルは指標またはその組み合わせの評価のみに基づいていることがあまりに多いのです。エントリーシグナルとエグジットシグナルに関しては、不利な状況下では後者がより重要な役割を果たします。

このブログでは、取引からの撤退、すなわちポジションの決済に焦点を当てます。私たちは、私たちの新しいとに関連する興味深いトピックをカバーしています。

オーダーAPIの改善 を使い、トラリピのコードエディターを使って、すべてをシンプルな取引戦略にまとめました。すべてのPythonコードは、ステップバイステップで説明されています。

なぜ出口ルールにこだわるのか?

トレードを終了するための判断ルールを設定することは、少なくともエントリーポイントのタイミングと同じくらい重要です。一般的に、エグジットシグナルは2つに大別されます。

  • シグナル駆動型出口ポジションの決済は、純粋に何らかの取引シグナル、すなわちインディケータ、クロスオーバー、その他のモデルシグナルの評価によって行われます。
  • 利益/時間に関連した終了。 ポジションを閉じることは、何らかの(リスク調整された)収益性指標および/または時間に関連する要素(例:X日後に閉じる)に基づく。

これらの2つの大雑把に定義されたカテゴリーは決して相互に排他的ではありませんが、このブログの記事で区別として使用するには十分なものです。

純粋にシグナルに基づく退出の主な問題は、トレーダーが退出シグナルを受け取るまで損益勘定が大きく変動することを快く思わない可能性があるということです。そのため、ほとんどのアルゴリズム取引戦略には、利益と損失に対してある種の逆指値が含まれています。これらの制限は、何らかのリスク指標(例:ボラティリティ)と連動していることが非常に多いのです。さらに、一部の投資戦略では、特定のポジションの最大保有期間を導入することもあります。

アルゴリズム取引におけるストップリミットの重要性に鑑み、ここでは、以下の実装に焦点を当てます。 利益/損失と時間に関連した出口 を使って 新しいTrality Order API.

三重バリア方式

M. Lopez de Pradoが1965年に発表したTripple-Barrier Method(トリプルバリア法)。 金融機械学習の進歩は、金融時系列のラベリング手法である。これは、タッチされた最初の障壁のリターンの符号を予測するために教師あり機械学習アルゴリズムで使用することができます。

この後のセクションでは、ラベルを推定するために機械学習を使用するのではなく、取引を終了するための決定ルールとしてこのメソッドを使用することに注意してください。

この方法をよりよく理解するために、グラフで可視化することができます。

Lopez de Pradoの三重障壁法をグラフィックで可視化したもの。
ソースはこちら mlfinlab

Tripple-Barrier-Method の名前が示すように、3つの境界を見ることになります。

  • テイクプロフィット・バリア最上段の水平破線
  • ストップロスバリア最下段の水平破線
  • タイムバリア: 右の破線縦線(最大保持期間)

Python APIを使用することで、いかに簡単に実装できるかを確認するために、この終了ルールを段階的に分解していきます。まず イフタッチされた成行注文という注文があり、これがバリアー法のキーとなる注文タイプになります。第二に、その概念について説明します。 注文の範囲, というように、注文を連鎖させることができます。最後に、これがどのように簡略化されたトレーディングボットに使用されるかを紹介します。

ストップ注文の送信

新しい注文APIでは、注文の作成を可能な限り簡素化するよう努めました。成行注文、指値注文、イフタッチ注文、トレール注文など、一般的に利用可能なすべての注文タイプを送信することができます。また、ほとんどの注文タイプには、3種類の数量設定タイプがあります。より詳細な説明と機能については、以下のサイトをご覧ください。 Trality ドキュメント.ここで、終了ルールを実装するためのキーオーダータイプについて見てみましょう。

イフタッチ成行注文

If-touched 成行注文は、条件付き注文です。この注文は 成行注文 指定されたストッププライスに到達またはクロスした場合。交差の方向は、注文作成時に現在の市場価格を使用して解決されます。

これを単純化するために、次のような状況を想像してください。

イフタッチ成行注文のグラフィックな視覚化

BTC の現在の市場価格が 8840 USDT 前後で、9000 USDT で 3 BTC を売りたいとします。次のように if-touched 成行注文を使用することでそれが可能になります。

order_iftouched_market_amount("BTCUSDT",amount=-3,stop_price=9000)

これはすでに有用ですが、利食い設定においては、ストップをパーセントで指定する方がより自然だと思われます。そこで、使いやすいラッパー関数を2つ用意しました。

利食い

現在の市場価格よりstop_percent高いstop_priceで指定された金額のIf-Touched Market売り注文を作成します(take-profit)。

order_take_profit(symbol="BTCUSDT",amount=3,
				  stop_percent=0.05,subtract_fees=False)

ストップロス

現在の市場価格よりstop_percent低いstop_priceで指定された金額のIf-Touched Market売り注文を作成します(ストップ・ロス)。

order_stop_loss(symbol="BTCUSDT",amount=3,
				stop_percent=0.05,subtract_fees=False)

これらの便利な関数は両方とも、パラメータとして 減算料金. True` に設定すると、金額から為替手数料が自動的に差し引かれます。

特定の価格がタッチまたはブレイクされたときに実行される注文を送信する方法がわかったので、注文を一緒にリンクさせる方法が必要です。

注文スコープ

オーダースコープのコンセプトにより、オーダーをリンクさせ、その実行をコントロールする可能性を提供します。

トラリティでは、現在、2種類のオーダースコープを提供しています。

  • シーケンシャルです。 このスコープで作成された注文は、順番に厳密に実行されます。
  • 一方が他方を打ち消す。 このスコープで作成された注文は、リンクされた注文の1つが満たされるとすぐにキャンセルされます。

利用可能な注文スコープの詳細については、当社のドキュメントを参照してください。 こちら.

水平バリアの設定

One Cancels Other」オーダースコープは、まさに私たちのトリプルバリアエグジットメソッドに必要なものです。

当面は、垂直バリアを無視して、利益確定と損失確定のバリアを処理するための適切な関数をどのように実装するかを見てみましょう。目標は、与えられたシンボルについて、この「二重のバリア」を作成する簡単な関数、金額と上限だけでなく下限バリアも得ることです。Pythonでどのようにこれを行うことができるかを見てみましょう。

def make_double_barrier(symbol,amount,take_profit,stop_loss,state):

    """make_double_barrier

    This function creates two iftouched market orders with the onecancelsother
    scope. It is used for our tripple-barrier-method

    Args:
        amount (float): units in base currency to sell
        take_profit (float): take-profit percent
        stop_loss (float): stop-loss percent
        state (state object): the state object of the handler function
    
    Returns:
        TralityOrder:  two order objects
    
    """

    with OrderScope.one_cancels_others():
        order_upper = order_take_profit(symbol,amount,
        								take_profit,
                                        subtract_fees=True)
        order_lower = order_stop_loss(symbol,amount,
        							  stop_loss,
                                      subtract_fees=True)
        
    if order_upper.status != OrderStatus.Pending:
        errmsg = "make_double barrier failed with: {}"
        raise ValueError(errmsg.format(order_upper.error))
    
    # saving orders
    state["order_upper"] = order_upper
    state["order_lower"] = order_lower
    state["created_time"] = order_upper.created_time

    return order_upper, order_lower

見てわかるように、このメソッドは与えられた入力情報を使って利益確定と損切りのバリアを作成し、関連する情報を 状態オブジェクト を作成しました。

私たちの注文範囲は、1つの注文が満たされた場合、他の注文はすぐにキャンセルされることを保証します。キャンセルが自動的に行われるので、個々の注文を追跡する必要はありません。

最大保有期間の追加

追加機能として、最大保有期間(つまり垂直バリア)を含めることができます。この方法は、ポジションが最大保有期間より長く保有されているかどうかをチェックするために、状態情報を使用するだけです。もしそうであれば、ポジションをクローズし、バリア注文をキャンセルします。

def check_max_holding_period(timestamp,state):
    
    """check_max_holding_period

    This function checks the for a first touch in the vertical barrier.
    If the vertical barrier is touched the double barrier orders are canceled.

    Args:
        timestamp (float): milliseconds of current engine time
        state (state object): the state object of the handler function          
    
    Returns:
        bool value

    """

    if check_state_info(state) is None:
        return True
    
    time_delta = timestamp - state["created_time"]
    
    if state["max_period"] is None:
        return True

    # cancel order if vertical barrier reached
    if time_delta >= state["max_period"]:
        print("vertical barrier reached")
        cancel_order(state["order_upper"].id)
        cancel_order(state["order_lower"].id)
        close_position(state["order_lower"].symbol)


    return True

上記の例では、単純な関数を使用して、必要なすべての情報のために状態オブジェクトをチェックしています。

def check_state_info(state):
    
    """check_state_info

    This function checks the state object for relevant order information.
    If the information exists it also refreshes the order_upper from the
    double barrier function

    Args:
        state (state object): the state object of the handler function          
    
    Returns:
        None or TralityOrder order_upper 

    Raises:
        
        AssertionError: If invalid order specification.
    
    """
    
    if "order_upper" not in state.keys():
        return None
    elif state["order_upper"] is None:
        return None
    
    order_upper = state["order_upper"]
    
    errmsg = "No max_period in state. Unable to check max holding period"
    
    assert "max_period" in state.keys() , errmsg
    # refreshing order from api
    order_upper.refresh()
    
    if order_upper.status != OrderStatus.Pending:
                
        # resetting state information
        state["order_upper"] = None
        state["order_lower"] = None
        state["created_time"] = None
        return None

    return order

すべてをまとめる

15分間隔で取引するペアBTCUSDTのシンプルな取引戦略にすべてをパッケージ化するために、開発したものを使用する準備が整いました。まず、ボットの簡単なエントリールールを定義しましょう。

エントリールール

私たちは価格シグナルとボリュームシグナルを定義します。両方が真であれば、BTCUSDTをロングする。

1) 価格シグナル
直近の5連続終値が上方ティック(アップティックと呼んでいます)。

テキスト{upticks} = \sum_{t = T-5}^{T} sign(close_t – close_{t-1})$$$ となります。

したがって、次のような場合に価格シグナルが成立することになります。 アップティック == 5.はい、これは簡単です。ちょっとしたヘルパー関数を書けばいいのです。

def last_five_up(data):
    prices = data.select("close")
    signs = np.sign(np.diff(prices))[-5:]
    return sum(signs) == 5

2) ボリューム信号
ボリュームシグナルを次のように定義する。

EMA(Volume,20) >EMA(Volume,40)$$.

いつものように、データオブジェクトを直接使うことができます。

ema_short_volume, ema_long_volume = volume.ema(20).last, volume.ema(40).last

    # return early on missing data
    if ema_short_volume is None:
        return False 
    
    has_high_volume = ema_short_volume[-1] > ema_long_volume[-1]

終了ルール

先ほどの説明で、利食い5%、損切り3%のトリプルバリア方式を使用します。最初の試みとして、最大保有期間を「なし」に設定し、パラメータを無視することにします。

ハンドラ関数

最後に、ハンドラ関数をコーディングして、アルゴリズム全体をまとめる準備ができました。資本の95%をエントリーシグナルにコミットする。


def initialize(state):
    state.max_period = None # exclude vertical


@schedule(interval="15min", symbol=["BTCUSDT"], window_size=200)
def handler(state, data):
    
    # moving averages on volume
    volume = data.volume
    ema_short_volume, ema_long_volume = volume.ema(20).last, volume.ema(40).last

    # return early on missing data
    if ema_short_volume is None:
        return False 
    
    has_high_volume = ema_short_volume[-1] > ema_long_volume[-1]

    # at every timestamp check max holding period
    check_max_holding_period(get_timestamp(),state)

    # getting portfolio and position information
    portfolio = query_portfolio()
    buy_value = float(portfolio.excess_liquidity_quoted) * 0.95
    position = query_open_position_by_symbol(data.symbol)
    has_position = position is not None
    
    if not has_position and last_five_up(data) and has_high_volume:
        price = data.close_last
        buy_amount = buy_value / price
        buy_order = order_market_amount(data.symbol,buy_amount)

        # setup barriers
        make_double_barrier(data.symbol,float(buy_order.quantity),
                            0.05,0.03,state)



サンプルバックテスト

コンセプトの説明のために、2020年1月の1ヶ月間、ボットを走らせてみます。これは決してストラテジーパフォーマンスの精巧な分析ではなく、あくまで簡単な例です。

Tralityを使ったバックテストの可視化

この期間が全く代表的でないとしても、利食いと損切りのバリアによっていくつかのドローダウンが回避されたことがわかります。これを見るために、私たちのポジションを見てみましょう。

ポジションの可視化、ドローダウンの分析

当社のバックテスト・システムは、IFタッチした注文をそれぞれのストッププライスで正確に決済することに留意してください。この単純化は本番の取引では保証されません。

もちろん、これは単純化しすぎです。エントリーポイントとエグジットポイントを見れば、すでに改善の余地があることがわかります。

エントリーポイントとエグジットポイントをグラフィックで可視化

この場合、我々はかなり幸運です。ほとんどの場合、退場後、価格は本当に下がります。しかし、もし利食いバリアが発動されたら、その直後に再びエントリールールが発動される可能性があります。最悪の場合、価格が急落する直前にエントリーする可能性もある。

まとめ

このブログ記事では、より現実的な性格を持ち、金銭的な損失と利益に対する自然なリスク回避に密接に関連する、代替の出口ルールを紹介します。このブログの焦点は、当社の新しい注文APIを理解し、それをどのように使用できるかを示すことでした。


免責事項 この記事に記載されている内容は、投資アドバイスとみなされるべきものではありません。 上記の記事は単なる意見であり、投資方法、取引方法に関するいかなる取引上の助言または提案を示すものではありません。, どの資産に投資するか または提案 について トレーディングボットやトレーディングアルゴリズムがどのように使用できるのか、または使用すべきなのかd!投資する前に必ず自分自身で調査し、必ず(!)損してもいい額だけを投資しましょう! バックテストは将来の結果を示唆するものではありません。.

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!
目次