English Русский 中文 Español Deutsch Português Italiano
市場の数学:利益、損失、コスト

市場の数学:利益、損失、コスト

MetaTrader 5 | 28 11月 2022, 13:35
594 0
Evgeniy Ilin
Evgeniy Ilin

内容

はじめに

エキスパートアドバイザー(EA)を開発するとき、損益を計算する際に特定の数値が何を意味するのかはまったく気に留めていませんでした。EAを作成するのに、この問題を掘り下げて考える必要はありません。確かに、MQL5が(MQL4でさえ)計算に必要な関数をすべて備えているのに、なぜこれらの値をすべて把握しなければならないのでしょうか。

しかし、ある一定の時間と経験を経ると、どうしても疑問が湧いてくるものです。やがて、それまで些細なことにしか見えなかったそのような細部にまで気がつくようになります。よくよく考えてみると、EAというのは、現物を見ずに品物を買うようなものだということがわかります。インターネットで調べたところ、この問題に関するデータはどれも乏しく、構造化されていないことがわかったので、自分で構成することにしました。この記事を読めば、注文に関するあらゆることを理解して正しく計算することができるようになるとともに、完全で実用的な数学的モデルを手に入れることができます。

注文の利益または損失の方程式

効率的な取引システムを開発するためには、まず、各注文の損益がどのように計算されるかを理解する必要があります。私たちは皆、資金管理システムを維持するために、どうにかして利益と損失を計算することができます。直感的にやる人、ざっくりとした見積もりをする人など様々ですが、ほとんどのEAでは必要な数量をすべて計算しています。

EAの開発は、自分の思考を鍛え、何がどのように計算されているのかを理解させる貴重なものです。さて、本題に入りましょう。まず、注文の利益がどのように計算されるのか、最も単純な考え方から始めるとよいでしょう。利益の計算は本質的にかなり複雑であるがいくつかの単純な考察に基づいていることは、個人的には以前から知っていました。理解を容易にするために、スプレッド、スワップ、手数料が存在しないと仮定します。多くの人は、初めはこの価値観を考慮することもないと思います。もちろん、MQL5言語にはOrderCalcProfitのような組み込み関数があり、他にもあるかもしれませんが、この記事では、何がどのように計算されるのかを誰もが理解できるように、基本的なことを説明したいと思います。ただし、スプレッドや手数料、スワップといったパラメータに注意を払わないことは、多くのトレーダーが犯している致命的なミスです。これらの数値は、それぞれ独自の方法で損益に影響を及ぼします。私の計算では、すべてを考慮し、そのような小さなことがいかに役に立つかを示していきます。以下は、スプレッド、手数料、スワップを除く注文の損益です。

  • PrBuy = Lot * TickValue * [ ( PE - PS )/Point ] - 買い注文の利益
  • PrSell = Lot * TickValue * [ ( PS - PE )/Point ] - 売り注文の利益
  • Point - 選択された銘柄の価格の最小変化量
  • TickValue - 価格が1ポイント動いたときの利益を生むポジションの利益値
  • PE - 取引終値(Bid)
  • PS - 取引始値(Bid)

MQL5のPointやTickValueのような値は、定義済み変数のレベルで定義されているか、SymbolInfoDouble型関数の戻り値の形として組み込み関数で利用可能です。MQL5またはその特定の関数がどのように構築されているかを分析するだけで多くの問題の根底に到達できることが多いため、記事内では定期的にMQL5のトピックに何らかの形で触れます。

次に、この方程式の理解を少し広げてみましょう。買い注文はAsk、売り注文はBidで出されます。買い注文はBidで決済され、売り注文はAskで決済されます。新しい補正を考慮して方程式を書き直しましょう。

  • PrBuy = Lot * TickValue * [ ( Bid2 - Ask1 )/Point ] - 買い注文の利益
  • PrSell = Lot * TickValue * [ ( Bid1 - Ask2 )/Point ] - 売り注文の利益
  • Bid1 - 売り取引の始値
  • Ask1 - 買い取引の始値
  • Bid2 - 買い取引の終値
  • Ask2 - 売り取引の終値

以下の仕様の断片には、後で必要となるデータのほとんどが含まれています。

必要なデータ

これは計算に必要なデータの一部に過ぎません。残りのデータは、MQL5のさまざまな組み込み関数を使用して取得することができます。USDJPYを例にとって考えてみましょう。実は、コードを書くのに仕様書は必要ないのですが、このデータがどこに表示されるかを理解することは非常に有効かもしれません。

今回は手数料の検討を進めましょう。注文ごとの手数料はさまざまな方法で計算できますが、主な方法はすべて、取引ロットに対する割合に帰着します。他にも取引手数料を徴収する方法はありますが、ここでは必要ないので割愛します。手数料の計算方法について、2つの可能性を考えてみます。それで十分だと考えています。スワップを基本とするならば、スワップの例は、手数料に適用できるもう1つの一般的な計算方法であるポイントでの計算を示唆するかもしれません。

その結果、一見すると異なる2つの方法が得られます。しかし、後述するように、これらの方法は、スプレッドも含めて同じ「課金」の方法を都合よく認識したものに過ぎません。以下は、手数料を計算するための2つの方程式です。

  1. Comission = Lot * TickValue * ComissionPoints
  2. Comission = Lot * ContractSize * BidAlpha * ComissionPercent/100

ここには、新しい値ContractSizeがありますが、この値もMQL5では取引サーバーから情報を受け取る組み込み関数のレベルで実装されています。この値は最も重要なものの1つで、プログラマーの計算を簡単にするため、暗黙の形式ではありますが、絶対にすべての損益計算に含まれます。プログラマーの立場からは、このような単純化の妥当性が見えますが、ここでの現在の目的は、すべてを理解することです。なぜこれが必要なのかは、記事の最後のほうに書いてあります。それに、BidAlphaという変数も追加で導入しています。以下でその意味も明らかにします。また、銘柄仕様で指定された以下の値も現れます。

  • ComissionPoints - ポイント単位の手数料
  • ComissionPercent - 契約サイズに対する手数料の割合
BidAlpha乗数は、基軸通貨単位のスワップを預金通貨単位のスワップに換算するために必要です。ここには、4つのシナリオがあります。
  1. BidAlpha = 1 (基軸通貨と預金通貨が同じ場合)
  2. BidAlpha = Bid(選択した銘柄の場合)
  3. BidAlpha = Bid(対応するレートのうち、選択した銘柄の基軸通貨が変換銘柄の基軸通貨と同じで、決済通貨が預金通貨と同じである場合)
  4. BidAlpha = 1/Ask(対応するレートのうち、選択した銘柄の基軸通貨が変換銘柄の決済通貨と同じで、基軸通貨が預金通貨と同じである場合)

確かに、契約サイズをUSDCHFのペアに適用すると、選択したペアの基軸通貨がUSDであることは明らかです。仮にUSDで預金しているとすると、決済通貨はUSDUSDとなり、従ってそのレートは常に1です。2つ目のケースは、さらにシンプルです。EURUSDのペアがあるとします。これは為替レートでもあるので、そのBidは必須値です。3つ目のケースは、こんな感じでしょうか。通貨がEURNZDであるとします。そうすると、EURとUSDからの為替レートを求めなければならないことがわかります。EURUSDのレートとこのレートのBidが必要です。4つ目のケースは、もう少し複雑です。仮にCHFJPYを選択したとします。ForexにCHFUSDの為替レートが存在しないため、変換ペアがUSDCHFであることは明らかです。もちろん、独自の合成銘柄を作成し、CHFUSDで作業することも可能です。この場合、先ほどのケースを利用することができます。しかし、実はこの銘柄をひっくり返すだけで、そのレートは現在の「不都合な」レートの「1/Ask」に等しくなるのです。実際のところ、それにこだわらずに合成銘柄を作るのです。スワップについても同じことが言えます。他にもいくつか質問があります。例えば、変換通貨では、Bid、Ask、Midのどのレートを使うべきかということです。この問題は、現在のアプローチの中では解決できませんが、その過程で、徐々に正しい方法を考えていくことになります。次に、少なくともおおよその改善のための枠組みを定義しましょう。そのためには、スプレッド、スワップ、手数料など、すべての「課金」オプションを考慮して、一般的な損益方程式の少なくとも最初の近似版を書いておく必要があります。

スワップを計算するには、同様の方程式があります。

  1. Swap = Lot * TickValue * SwapPoints * SwapCount(StartTime,EndTime)
  2. Swap = Lot * ContractSize * BidAlpha * SwapPercent/100 * SwapCount(StartTime,EndTime)

確かに方程式はかなり似ています。唯一の違いは、ある種の乗数が、ここではSwapCount関数という形で登場したことです。用語の自由をある程度認めていただきたいと思います。スワップを「関数」と呼んでいるのは、すぐに課金されるわけではなく、その大きさが注文の開始時間と終了時間に依存するためです。概算の場合、もちろん乗数を使わず、次のように書くことができます。

  • SimpleCount = MathFloor( (EndTime -StartTime) / ( 24 * 60 * 60 ) )

EndTimeとStartTimeがdatetime型であると仮定すると、それらの差は注文が出されてから決済されるまでの秒数に等しくなります。スワップは1日1回課金されるので、この値を1日の秒数で割れば大丈夫です。こうすることで、スワップポジションを評価する方法の最初の一歩を踏み出すことができます。もちろん、この方程式は完璧とは言いがたいですが、どんな関数で、何を返すのかという問いに対する答えを与えてくれます。その上、スワップがどのように(少なくともおおよそ)計算されるかを示唆することができます。これは、ポジションのライフタイム中に発生したスワップの回数を返します。同様に、仕様書に記載される手数料は、計算方法の表示が義務付けられているスワップについて、2つの可能な値のうちの1つとなります。

  • SwapPoints - ポイント単位での単一ポジションのロールオーバーのスワップ
  • SwapPercent - 契約サイズの割合での単一ポジションのロールオーバーのスワップ

手数料の場合は方程式が単純で説明の必要がないとすれば、スワップの場合はすべてがはるかに複雑ですが、この単純化の微妙なニュアンスについては後で説明します。まず、手数料やスワップを除いた損益方程式を、より整合性のある形にしてみましょう。

  • PrBuy = Lot * TickValue * [ ( Bid2 – (Bid1+S1*Point) )/Point ] - 買い注文の利益
  • PrSell = Lot * TickValue * [ ( Bid1 – (Bid2+S2*Point) )/Point ] - 売り注文の利益
  • S1 - 買い注文を出すときのスプレッド
  • S2 - 売り注文を決済するときのスプレッド

AskにはスプレッドとBidの両方が含まれることは明らかです。注文の結果の損益をスプレッドから分離し、別の数式にしてみましょう。

  • PrBuy = Lot * TickValue * [ ( Bid2 – Bid1)/Point ] + ( - Lot * TickValue * S1 ) - 買い注文の利益
  • PrSell = Lot * TickValue * [ ( Bid1 – Bid2)/Point ] + ( - Lot * TickValue * S2 ) - 売り注文の利益

どちらの式でも、ある方程式が分離されていることがわかります。それは、証券会社から請求された部分です。もちろん、これが全額ではありませんが、少なくとも、私たちが何を得て証券会社が何を得るのか、より明確におわかりいただけたと思います。最初のケースでは、スプレッドに対する「課金」は、「買い」ポジションを建てるときのスプレッド値のみに依存し、2番目のケースでは、「売り」ポジションを決済するときに依存することに留意してください。常に、買う時にきっちりスプレッドの形で利益の一部を証券会社に渡していることがわかります。実際、FX取引を深く掘り下げると、買いポジションを建てることと売りポジションを決済することは、式で確認されるように同等の行動であることがわかります。この場合:

  • S1 - ポジションを建てる際のスプレッド(ポイント単位)
  • S2 - ポジションを決済する際のスプレッド(ポイント単位)

スプレッドを表示する場合、これらの値はまさに気配値表示ウィンドウに表示される値です。対応する組み込みのSymbolInfoInteger MQL5関数は、対応する入力でまったく同じ値を返します。入力方法はMQL5のヘルプに記載されています。この場合、私の仕事は、MQL5言語と結びついた便利な数学的計算モデルを作成し、これらの方程式をEAやその他の有用なMQL5コードに即座にコード化できるようにすることです。ここで、スワップと手数料の両方に類似した数式ができました。

  • SpreadBuy = - Lot * TickValue * S1
  • SpreadSell = - Lot * TickValue * S2

開閉時のスプレッド

従来、スプレッドは買いの時点で計算されていますが、なぜそれが間違っているのかを説明します。いろいろと市場調査をした結果、最も値動きが予測しやすいポイントは「0時0分」であることがわかりました。これは、ある日から別の日への移行点です。この点を注意深く観察すると、どの通貨ペアでもほぼ同じで、つまりレートが下降する方向にジャンプしていることがわかります。これは、この時点でスプレッドが拡大したために起こります。ジャンプの後は、同じようにロールバックします。スプレッドとは何でしょうか。スプレッドとは、BidとAskの間のギャップのことです。従来、このギャップは市場の深さの結果であると考えられていました。市場の深さが指値注文で飽和するとスプレッドはゼロになる傾向があり、プレイヤーが市場からエグジットするとスプレッドは増加します。これを市場の深さの崩壊と呼ぶことができます。一見したところ、ここではBidが主要なものではないことがわかります。AskとBidは基本的に対等であることがわかります。これは、例えば「EURUSD」から「USDEUR」のミラー商品を構築し、BidがAskに逆にAskがBidになると想像するとわかりやすいと思います。簡単に言うと、市場の深さを反転しているだけです。

Askの線は、便利ではありますが、通常、チャートには表示されません。

bid & ask

見てわかるように、チャート期間の増加とともに、AskとBidが融合し始めます。おそらく、両方の行を表示するターミナルがないのはこれらの配慮からだと思われますが、個人的には必要なオプションだと思います。ただし、EAで利用することはできるので、これらの値の存在や違いについて知ることはそれほど重要ではありません。ここではMidを描いていませんが、この線がBidとAskのちょうど真ん中であることは、皆さんもご理解いただけると思います。明らかに、長期間ではこれらの値の差は実質的に意味をなさないので、Askの存在すら考慮する必要がないように思えますが、実は必要なのです。これらの詳細は非常に重要です。

このように考えると、市場の深さの真ん中は、このような変換の際に不変なものであると、絶対的に言えるようになったのです。この値は、以下のように計算することができます。

  • Mid = (Ask + Bid) / 2

このような表現を考え、最後の式を用いると、次のようになります。

  • Bid = Mid * 2 – Ask
  • Ask = Mid * 2 - Bid

次:

  • Bid = Mid * 2 – (Bid + S*Point) = Mid – (S*Point)/2
  • Ask = Mid * 2 – (Ask - S*Point) = Mid + (S*Point)/2

これらの式は、元の注文の損益を計算する式に代入することができます。こういう表現をきっちりすることが大事だったのは、今までわからなかったことを見せたいからです。証券会社からの課金額は、実は買いの時点だけでなく、エントリの時点とエグジットの時点の両方、またどのポジションにも依存することがわかったのです。そこに新しい拡張定義を挿入すると、式がどうなるか見てみましょう。次のコードを参照してください。

  • PrBuy = Lot * TickValue * [ ( (Mid2 – (S2*Point)/2) – (Mid1 + (S1*Point)/2) ) )/Point ]
  • PrSell = Lot * TickValue * [ ( (Mid1 – (S1*Point)/2) – (Mid2 + (S2*Point)/2) ) )/Point ]

適当な変換をすると、このようになります。

  • PrBuy = Lot * TickValue * [ (Mid2 – Mid1)/Point ] - Lot * TickValue * (  S1/2 + S2/2  )
  • PrSell = Lot * TickValue * [ (Mid1 – Mid2)/Point ] - Lot * TickValue * (  S1/2 + S2/2  )

次を考慮し、

  • Bid1 = Mid1 – (S1*Point)/2
  • Bid2 = Mid2 – (S2*Point)/2
  • Ask1 = Mid1 + (S1*Point)/2
  • Ask2 = Mid2 + (S2*Point)/2

次を念頭に置き、

  • Mid1 - 任意のポジションを建てるときの市場の深さの真ん中
  • Mid2 - 任意のポジションを決済するときの市場の深さの真ん中

便宜上、スプレッドによる損失を定義する負の数式を以下のように表記します。

  • Spread = -Lot * TickValue * (  (S1*Point)/2 + (S2*Point)/2  )

また、それに伴い、例えば、スプレッド、手数料、スワップなどを除いた損益を示す数式は次のようになります。

  • ProfitIdealBuy = Lot * TickValue * [ (Mid2 – Mid1)/Point ]
  • ProfitIdealSell = Lot * TickValue * [ (Mid1 – Mid2)/Point ]

これで、スプレッド、手数料、スワップによる損失をすべて考慮した便利な方程式が書けるようになりました。まず、式のプロトタイプから見てみましょう。ここではスプレッドだけを考慮して、最新の注文損益式をベースに考えてみましょう。

  • TotalProfitBuy = ProfitIdealBuy + (Spread + Comission + Swap)
  • TotalProfitSell = ProfitIdealSell + (Spread + Comission + Swap)

もしかしたら、この式は一番最初に書くべきだったかもしれませんが、ここでの方が適切だと思います。曖昧なTickValueがほぼ全域に存在することがわかります。主な問題は、その計算方法と、異なる時点で1つの同じ値を用いて計算することができるかということです。タイムポイントとは、ポジションのエントリおよびエグジットを意味します。この値は動的なものであり、しかも各取引銘柄ごとに異なることは理解していただけると思います。この値を構成要素に分解しないと、「ターゲット」が遠ければ遠いほど誤差が大きくなります。つまり、得られた方程式はあくまで近似値です。このような欠点がない、絶対的に正確な方程式があります。上記で得られた比率は、その限値となります。限値そのものは次のように表現できます。

  • Lim[ dP -> 0 ] ( PrBuy(Mid1, Mid1+dP... ) ) = TotalProfitBuy(Mid1, Mid1+dP...)
  • Lim[ dP -> 0 ] ( PrSell(Mid1, Mid1+dP... ) ) = TotalProfitSEll(Mid1, Mid1+dP...)
  • Mid1+dP = Mid2 - 新しい価格は、前の価格にゼロになる傾向のデルタを加えたもの
  • TotalProfitBuy = TotalProfitBuy(P1,P2... ) - 決定されたように、損益はMid値やその他多くの関数
  • TotalProfitSell = TotalProfitSell(P1,P2...) - 同様

一般に、一般的な理解のための等価限値は、いろいろな方法で導き出すことができます。乗算する必要はありません。ここでの場合、わかりやすくするために1つで十分です。

いくつかの方程式を受け取り、それが動作することもありますが、適用できる限界は非常に条件的なものです。次に、このような近似方程式を伴う初期方程式を求める作業に従事することになります。利益や損失がどのような構成要素で成り立っているのかを知らなければ、これらの方程式を得ることはできません。これらの方程式は、損益計算のための最も正確な比率を見つけるだけでなく、市場プロセスのアンバランスを見つけ出し、その後に利益をもたらすことができます。

注文の損益を最も正確に計算する方法

このような方程式を構築する方法を理解するためには、「買い」と「売り」とは何かという基本に立ち返る必要があります。しかし、その前に、「買う」ということは、実は「商品とお金を交換する」ということだということを忘れてはいけないと思うのです。別の通貨は特定の商品を所有する能力を象徴しているため、商品と見なすことができます。そうすると、売ることは2番目の通貨と1番目の通貨を交換する逆のプロセスであることがわかります。ただし、すべての慣習を省けば、買うことと売ることは同等の行為であることがわかります。ある通貨を別の通貨と交換し、どの通貨を渡し、どの通貨を受け取るかの違いだけです。

この計算について情報を探しているうちに、私自身、根拠がないために長い間把握できなかった不思議な慣例が見えてきました。私は技術屋で、さまざまな技術資料を研究してきた経験があるので、非常に単純な2つの真実を判断しました。もし、この資料が読者にとって明確でなく、疑問を投げかけるものであれば、次を参照してください。

  • 著者自身が完全に理解しているわけではないので、あらゆる手段で反対を納得させることに全力を尽くす(これは通常、反論理的な文言を用いておこなわれます)
  • 詳細については、読者に不要な情報を伝えしないよう、意図的に省略している

下の画像は、その考えをさらに発展させたもので、より分かりやすくなっています。2種類の成行注文の開始と終了が表示されています。

売買

これで、スプレッドセクションと現在のセクションが明確になると思います。一般に、この画像は記事全体に関係しますが、このブロックでは最も有効です。

もちろん、専門的な文献には正しい計算があるのでしょうが、その情報を探すのは、自分で足りないものを推測するよりも難しいのは明らかです。慣例では、例えばEURUSDを買う場合、EURを買い、USDを売ることになります。書き出してみましょう。

  • EUR = Lot * ContractSize
  • USD = - Ask1 * Lot * ContractSize = - (Bid1 + S1*Point) * Lot * ContractSize

この場合、買う時に基軸通貨をプラス、決済通貨をマイナスで表すことがわかります。これはまったくナンセンスだと思うのは、私だけではないでしょう。いろいろ考えた結果、「比率は正しいが、ちょっとわかりにくい表現になっている」という結論に達しました。EURを買うには、USDが必要で、バランスシートから取るか、証券会社から借りるか、両方の方法を使うことになります。つまり、まずどこかの共有ストレージからUSDを借りてくるのです。次のようになります。

  • USD1 = Ask1 * Lot * ContractSize = (Bid1 + S1*Point) * Lot * ContractSize - 借りたもの
  • EUR1 = Lot * ContractSize - 買った時のAsk為替レートで借りた資金で買ったもの

マイナスの値は後で現れます。実は、今ここにあるはずがないのです。マイナスの値は、ポジションを決済するときに現れます。ポジションが開いているのであれば、決済する必要があります。売りのアクションは同じロットで実行する必要があることがわかりました。標準的な考察を忠実に守れば、次のようになります。

  • EUR2 =  Lot * ContractSize
  • USD2 = Bid2 * Lot * ContractSize

すでにEURを売ってUSDを買っていることがわかります。私たちの変換は、借りた資金を自分から交換したユーロを、借りた通貨に戻すことです。受取資金から借入資金を減算することで、利益または損失が得られます。

  • Profit_EUR = EUR1 – EUR2 = 0
  • Profit_USD = USD2 – USD1 = Bid2 * Lot * ContractSize - (Bid1 + S1*Point) * Lot * ContractSize = Lot * ContractSize * ( Bid2 – Bid1 – S1*Point)

EURが消え、USDだけが残ることがわかります。預金が米ドルの場合、預金通貨は同じなので、結果の通貨を預金通貨に換算する必要はありません。この式は、一番最初に基礎とした式と非常によく似ていますが、唯一違うのは、手数料とスワップは別々に考えられるので、ここでは考慮されていないことです。ここで、この式を少し書き換えてみましょう。

  • Profit_USD = Lot * (ContractSize*Point) * [ ( Bid2 – Bid1 – S1*Point) / Point ]

ここでは、右辺をPointで割って掛けただけで、ば元の式が得られます。この式は、「売買の方向に関係なく、同時に売買する」という本来の規約があるシステムを使っても、同じ式が得られます。この場合、借りたものには借りたことを象徴するマイナス記号がつき、買った金額にはプラス記号が残ります。このような規約があるシステムでは、何をどこから何に変えるかを考える必要はありません。この手法で同じことをやってみましょう。

  • EUR1 = Lot * ContractSize
  • USD1 = - Ask1 * Lot * ContractSize = - (Bid1 + S1*Point) * Lot * ContractSize

これは買いです。アクション1:

  • EUR2 = - Lot * ContractSize
  • USD2 = Bid1 * Lot * ContractSize

これは売りです。アクション2:

さらに言えば、何から何をどう減算するかを考える必要がないので、すべてがシンプルになるのです。EURとUSDを別々に加算すればいいだけです。基軸通貨はとにかく消え、決済通貨だけが残ります。加算をして、前の式と同じになるようにしましょう。

  • Profit_EUR = EUR1 + EUR2 = 0
  • Profit_USD = USD1 + USD2 = - (Bid1 + S1*Point) * Lot * ContractSize + Bid2 * Lot * ContractSize = Lot * ContractSize * ( Bid2 – Bid1 – S1*Point)

どの銘柄も利益は(基軸通貨ではなく)決済通貨のみで考慮され、基軸通貨は全開閉サイクルの間に常に消滅することがわかりました。当然、売るためにはすべてがミラーリングされています。これを全部書いて、計算を完了させましょう。ここでEURUSDを売り、「買い」を実行してこのポジションを決済します。

  • EUR1 =  - Lot * ContractSize
  • USD1 = Bid1 * Lot * ContractSize

これは売りです。アクション1:

  • EUR2 = Lot * ContractSize
  • USD2 = - (Bid2 + S2*Point) * Lot * ContractSize

これは買いです。アクション2:

では、同じようにすべての値を足してみましょう。

  • Profit_EUR = EUR1 + EUR2 = 0
  • Profit_USD = USD1 + USD2 = Bid1 * Lot * ContractSize - (Bid2 + S2*Point) * Lot * ContractSize = Lot * ContractSize * ( Bid1 – Bid2 – S2*Point)

見ての通り、方程式の違いはBid1とBid2が入れ替わっていることです。そしてもちろん、スプレッドはポジションの終値で請求されます。終値は買いポイントだからです。今のところ、すべて元の方程式に忠実に再現されています。また、少なくとも銘柄の決済通貨(基軸通貨ではない)が預金通貨と一致する場合、TickValueが何であるかが分かったことは注目に値します。この値の方程式を書いてみましょう。

  • TickValue = ContractSize * Point

ただし、この値は、利益の通貨が預金通貨と等しい銘柄にのみ適していますが、例えばAUDNZDのようなクロスレートを使う場合はどうでしょうか。ここで重要なのは、銘柄そのものではなく、この値が常に預金通貨との関係で計算され、取引サーバーから受け取るという事実です。しかし、この方程式をクロスレートとの関係で使ってみると、もちろん機能するのですが、預金通貨ではなく、銘柄の決済通貨で応答してくることがわかります。これを預金通貨に換算するためには、この値に一定の比率をかける必要があるのですが、実はこれが前のブロックで検討した為替レートなのです。

  • TickValueCross = ContractSize * Point * BidAlphaCross

為替レートの計算はとてもシンプルです。

  1. 銘柄の決済通貨に注目する(基軸通貨でない)
  2. この通貨と預金通貨が含まれている銘柄を探す
  3. 適切なレートで交換する
  4. 必要に応じて、銘柄を変形させる(ミラーコース)

例えば、EURCHFを取引し、預金通貨がUSDの場合、最初の利益はCHFになるので、USDCHFの商品とそのレートを使用することができます。つまり、CHFをUSDに換算した後、CHFのためにUSDをj買う必要があることがわかりました。しかし、CHF = PBid * USDなので、USD = (1/PAsk) * CHFとなり、それに応じて次のようになります。

  • BidAlphaCross = 1/PAsk

2つ目の例では、別の銘柄を使ってみましょう。例えば、AUDNZDを取引し、NZDで利益を得た場合、NZDUSDのレートを取ります。USD = PBid * NZDなので、この場合、次のようになります。

  • BidAlphaCross = PBid

考えてみましょう。CHFをUSDに換算する場合は、「+USD ; -CHF」となります。つまり、ある通貨を失い、別の通貨を得るということです。これは、PAskの価格でUSDを買ってUSDCHFのレートで売るということで、実際には次のような意味しかありません。「USD = (1/PAsk) * CHF 」。それは次のように知覚するほうが容易です。買いの際に、私たちは、証券会社が私たちの換算操作から何も取らなかった場合よりも少し少ない米ドルを受け取ります。つまり、より大きなPAskで割ると、1/Pより小さな値が得られます。

2つ目のケースでは、状況が逆転します。NZDをUSDに換算すると、「+USD ; -NZD」となり、NZDUSDのレートを使ってPBid価格で売ることになります。USD = PBid * NZD」にも同様のレートを設定しましょう。再び少し悪い「PBid」レートで換算します。すべてが一致します。すべてが透明で、把握しやすいです。メインな完璧なレートは、上で考察した「PMid」であることを念頭に置いてください。そう考えると、スプレッドとは証券会社が換算する通貨の形で手数料を取る割合にほかならないことが理解できるのではないでしょうか。そのため、ポジションを建てるにしても決済するにしても、それぞれの取引にはスプレッドと呼ばれる証券会社の為替取引にかかる課金されます。この課金の残りは、手数料とスワップ料に含まれています。

為替レートは不要で、利益通貨と預金通貨が一致した場合のみ比率が1となるため、主要通貨ペアの場合は比率がなくなり、すべての通貨ペアでティックサイズが一定になります。先程と同じように、取引銘柄が変換レートであることがわかることもあるので、他の銘柄の中から探す必要はないです。

新しいBidAlphaCrossの値があることを考慮して、手数料とスワップを除いた注文損益方程式を書き直します。

  • BuyProfit = BidAlphaCross * Lot * ContractSize * ( Bid2 – Bid1 – S1*Point)
  • SellProfit = BidAlphaCross * Lot * ContractSize * ( Bid1 – Bid2 – S2*Point)

次を考慮した上で

  • Bid1 = Mid1 – (S1*Point)/2
  • Bid2 = Mid2 – (S2*Point)/2

Midに比を代入して、より視覚的な形に方程式を書き換えてみましょう。

  • BuyProfit = BidAlphaCross * Lot * ContractSize * ( Mid2 – (S2*Point)/2 – Mid1 + (S1*Point)/2 – S1*Point)
  • SellProfit = BidAlphaCross * Lot * ContractSize * ( Mid1 – (S1*Point)/2 – Mid2 + (S2*Point)/2 – S2*Point)

すべてを単純化しましょう。

  • BuyProfit = Lot * BidAlphaCross * ContractSize * Point * [ ( Mid2 – Mid1 )/ Point  - ( S1/2 + S2/2 ) ]
  • SellProfit = Lot * BidAlphaCross * ContractSize * Point * [ ( Mid1 – Mid2 )/ Point  - ( S1/2 + S2/2 ) ]

さらに簡略化します。

  • BuyProfit = Lot * TickValueCross * [ ( Mid2 – Mid1 )/ Point ] - Lot * TickValueCross * ( S1/2 + S2/2 )
  • SellProfit = Lot * TickValueCross * [ ( Mid1 – Mid2 )/ Point ] - Lot * TickValueCross * ( S1/2 + S2/2 )

これで、より簡単で明確になったかと思います。スプレッドに関連する数式を意図的に削除して、ポジションや注文がいつまで有効であるかにかかわらず、これが正確に請求された値であることを確認できるようにしました。

スワップの正確な計算関数

残っているのは、スワップ方程式を明確にすることです。冒頭で得た方程式を思い出してみましょう。

  • Swap = Lot * TickValue * SwapPoints * SwapCount(StartTime,EndTime)
  • Swap = Lot * ContractSize * BidAlpha * SwapPercent/100 * SwapCount(StartTime,EndTime)

前回のブロックでは、TickValueは一桁の値ではなく、通貨ペアによって計算方法が異なることがわかりました。次が判断されました。

  • TickValue = ContractSize * Point

しかし、これは利益通貨が預金通貨と一致するペアにのみ機能します。より複雑なケースでは、以下の値を使用します。

  • TickValueCross = ContractSize * Point * BidAlphaCross

ここで、BidAlphaCrossもまた、預金通貨と選択された銘柄に依存する異なる値です。これらはすべて、上で定義したものです。これをもとに、標準定数を置き換えた最初のバージョンの方程式を書き直す必要があります。

  • Swap = Lot * TickValueCross * SwapPoints * SwapCount(StartTime,EndTime)

しかし、この方程式はまだ完璧とは言えません。これは、手数料やスプレッドと異なり、スワップはポジションを保有したまま、任意の回数だけ入金することができるからです。クロスレートの場合、スワップ発生時点ごとにBidAlphaCross値が変化するため、この値が若干異なることがわかり、1つのTickValueCross値ではスワップ全体を表現できないことがわかりました。2つの「課金」オプションのスワップ計算の完全な方程式を書いてみましょう。

  1. Swap = SUMM(1 … D) { Lot * (SwapPoints * K[i]) * TickValueCross[i] } - 交差したポイントごとに、発生したすべてのスワップのポイントの合計 0:00
  2. Swap = SUMM(1 … D) { Lot * ContractSize * BidAlpha[i] * (SwapPercent/100 * K[i]) * } - %

合計する配列は、次です。

  • K[i] = 1または3 - 比率が「3」の場合、トリプルスワップ発生日
  • TickValueCross[i] - 入れ替え点におけるティックサイズの配列
  • BidAlpha[i] - スワップ課金時における調整レートの配列

任意の注文に対するスワップ計算の例を見てみましょう。そのために、以下のような短い表記を導入します。

  • TickValueCross[i] = T[i]
  • BidAlpha[i] = B[i]
  • K[i] = K[i]

では、どのようにスワップを合計するのか、図解してみましょう。

スワップ計算


注文損益の計算について、考えられるすべての例を分析しました。

実践部分

このセクションでは、私たちの数学的モデルをテストします。特に、手数料やスワップを考慮しない損益計算の問題には、特に注意を払いたいと思います。覚えていらっしゃるかもしれませんが、クロスレートで利益を計算する場合、どの時点のTickValueCrossの値を計算すればいいのかを考えていました。この瞬間が、私がこれからテストするモデル全体の中で唯一の不確定要素なのです。そのために、まず数学的モデルを用いて注文の損益を計算する機能を実装し、ストラテジーテスターでテストし、その後に取引履歴の実際の注文データと計算結果を比較しましょう。最終的な目標は、私たちの数学的モデルをテストし、同時にOrderCalcProfitなどのMQL5参照関数と比較することです。

これらを評価するためには、4つの量を導入する必要があります。

  1. Real - 履歴からの注文利益
  2. BasicCalculated - OrderCalcProfit関数を使用して注文を開くときに計算されるのと同じ利益
  3. CalculatedStart - 注文を出す際に、私たちの数学的モデルを使用して計算された利益
  4. CalculatedEnd - 注文を決済する際に、私たちの数学的モデルを用いて計算された利益

これには、3種類の平均的な利益値の偏差が含まれます。

  1. AverageDeviationCalculatedMQL = Summ(0..n-1) [ 100 * MathAbs(BasicCalculated - Real)/MathAbs(Real) ]  / n : MQL5コードによる相対的な利益の偏差値
  2. AverageDeviationCalculatedStart = Summ(0.. n-1 ) [  100 * MathAbs(CalculatedStartReal)/MathAbs(Real) ] / n : 私たちのコードによる注文を出す際の相対的な利益偏差
  3. AverageDeviationCalculatedEnd =  Summ(0.. n-1 ) [  100 * MathAbs(CalculatedEnd Real)/MathAbs(Real) ] / n :私たちのコードによる注文を決済する際の相対的な利益偏差

これと同様に、3種類の最大偏差を入力することができます。

  1. MaxDeviationCalculatedMQL = Max(0.. n-1 ) [ (100 * MathAbs(BasicCalculated - Real)/MathAbs(Real))  ] - MQL5コードによる相対利益偏差
  2. MaxDeviationCalculatedStart =  Max(0.. n-1 ) [  (100 * MathAbs(CalculatedStart Real)/MathAbs(Real)) ]  - 私たちのコードによる注文を開く際の相対利益偏差
  3. MaxDeviationCalculatedEnd =  Max(0.. n-1 ) [  (100 * MathAbs(CalculatedEnd Real)/MathAbs(Real)) ]  - 私たちのコードによる注文を決済する際の相対利益偏差

ここで

  • Summ(0..n-1) - すべての「n」注文の相対偏差の総和
  • Max(0..n-1) - すべての「n」注文からの相対最大偏差

これらの計算を任意のEAのコードに実装することで、数学モデルを検証することができます。まず、利益方程式を実装することから始めましょう。私は次のような方法にしました。

double CalculateProfitTheoretical(string symbol, double lot,double OpenPrice,double ClosePrice,bool bDirection)
   {
   //PrBuy = Lot * TickValueCross * [ ( Bid2 - Ask1 )/Point ]
   //PrSell = Lot * TickValueCross * [ ( Bid1 - Ask2 )/Point ]
   if ( bDirection )
      {
      return lot * TickValueCross(symbol) * ( (ClosePrice-OpenPrice)/SymbolInfoDouble(symbol,SYMBOL_POINT) );
      }
   else
      {
      return lot * TickValueCross(symbol) * ( (OpenPrice-ClosePrice)/SymbolInfoDouble(symbol,SYMBOL_POINT) );
      }   
   }

ここでは、買いの方程式と売りの方程式の2つが1つになっています。bDirectionマーカーがこれを担っています。ティックサイズを計算する追加関数は、緑色で表示されます。ここでは以下のように実装しました。

double TickValueCross(string symbol,int prefixcount=0)
   {
   if ( SymbolValue(symbol) == SymbolBasic() )
      {
      return TickValue(symbol);
      }
   else
      {
      MqlTick last_tick;
      int total=SymbolsTotal(false);//symbols in Market Watch
      for(int i=0;i<total;i++) Symbols[i]=SymbolName(i,false);
      string crossinstrument=FindCrossInstrument(symbol);
      if ( crossinstrument != "" )
         {
         SymbolInfoTick(crossinstrument,last_tick);
         string firstVAL=StringSubstr(crossinstrument,prefixcount,3);
         string secondVAL=StringSubstr(crossinstrument,prefixcount+3,3);
         if ( secondVAL==SymbolBasic() && firstVAL == SymbolValue(symbol) )
            {
             return TickValue(symbol) * last_tick.bid;
            }
         if ( firstVAL==SymbolBasic() && secondVAL == SymbolValue(symbol) )
            {
            return TickValue(symbol) * 1.0/last_tick.ask;
            }         
         }
      else return TickValue(symbol);  
      }
   return 0.0;   
   }

また、内部は以下の2つのケースを想定して実装されています。

  1. 銘柄の利益通貨が預金通貨と同じ
  2. その他すべてのケース(変換レートを模索中)

2つ目のシナリオも2つのケースに分かれます。

  • 預金通貨が為替レートの上位にある
  • 預金通貨は為替レートの下位にある

すべては数理モデルに厳密に則っています。最後の部門を実施するためには、まず、為替レートを計算するための適切なツールを見つける必要があります。

string FindCrossInstrument(string symbol,int prefixcount=0)
   {
   string firstVAL;
   string secondVAL;
   for(int i=0;i<ArraySize(Symbols);i++)
      {
      firstVAL=StringSubstr(Symbols[i],prefixcount,3);
      secondVAL=StringSubstr(Symbols[i],prefixcount+3,3);
      if ( secondVAL==SymbolBasic() && firstVAL == SymbolValue(symbol) )
         {
         return Symbols[i];
         }
      if ( firstVAL==SymbolBasic() && secondVAL == SymbolValue(symbol) )
         {
         return Symbols[i];
         }      
      }
   return "";
   }

そのためには、銘柄名から基軸通貨 を「取り出す」方法を知っておく必要があります。

string SymbolValue(string symbol,int prefixcount=0)
   {
   return StringSubstr(symbol,prefixcount+3,3);
   }

そして、MQL5内蔵の関数を使って利益通貨を取得します。

string SymbolBasic()
   {
   return AccountInfoString(ACCOUNT_CURRENCY);
   }

最初の一致の前に、すべての気配値表示の銘柄の通貨と比較します。この機能を、注文を出すときと決済するときに利用することができるようになりました。よろしければ、下に添付したファイルで残りのコードもご覧ください。バックテスト終了後に偏差の計算を追加しました。ターミナルのログに書き込まれます。主要な28の通貨ペアとクロスレートをすべてテストし、その結果を表にまとめ、数学的モデルの性能を評価し、MQL5の実装と比較できるようにしました。結果は3つの条件ブロックに分けられました。最初の2つは以下のような感じです。

1・2ブロック

ご覧のように、最初の4つの通貨ペアについては、利益通貨が預金通貨と同じであるため、MQL5と私たちの実装の両方が完全に機能します。次に、基軸通貨と利益通貨が同じである3つの通貨ペアのブロックがあります。この場合、MQL5の実装が最も効果的ですが、それでも、注文を出すときの計算誤差は、決済するときの同じ誤差よりもはるかに大きいことが既に明らかです。これは、本当は注文が決済された時点で計算をおこなうべきであることを間接的に示しています。他の通貨ペアも見てみましょう。

ブロック3

ここでは、私の機能はMQL5の基本的なものに劣るものではありません。また、ポジションを決済する際の計算も、常により正確におこなえるようになったことは確かです。ただ、2つ目のブロックの1行目にゼロがあることだけは説明できません。いろいろな理由が考えられますが、間違っているかもしれませんが私のモデルとは関係ないように思います。手数料やスワップなどの方程式の確認については、必要ないと思います。この方程式には特に難しいところはないので、自信があります。

結論

今回は、断片的な情報のみを頼りに、ゼロから作り上げた数理モデルを考えてみました。このモデルには、主要な通貨ペアやクロスレートの注文を計算するために必要なものがすべて含まれています。このモデルはストラテジーテスターでテストされており、あらゆるEA、指標、便利なスクリプトにすぐに使用することができます。実は、このモデルの適用範囲は、利益や損失、コストの計算だけでなく、もっと広いのですが、これについては別の記事で紹介します。必要な機能や使用例は、表の作成に使用した研究用EAに記載されています。EAは記事に添付しています。ご自分で実行し、その結果を表と比較してみてください。何より、シンプルで論理的な「マニュアル」を作ることができたと思っています。



MetaQuotes Ltdによってロシア語から翻訳されました。
元の記事: https://www.mql5.com/ru/articles/10211

添付されたファイル |
データサイエンスと機械学習—ニューラルネットワーク(第02回):フィードフォワードNNアーキテクチャの設計 データサイエンスと機械学習—ニューラルネットワーク(第02回):フィードフォワードNNアーキテクチャの設計
フィードフォワード(予測制御)ニューラルネットワークについて説明する前に、少し説明しておくことがあって、設計もその1つです。入力、隠れ層の数、および各ネットワークのノードに対する柔軟なニューラルネットワークを構築および設計する方法を見てみましょう。
ニューラルネットワークが簡単に(第25部):転移学習の実践 ニューラルネットワークが簡単に(第25部):転移学習の実践
前々回、前回と、ニューラルネットワークのモデルを作成・編集するためのツールを開発しました。いよいよ転移学習技術の利用可能性を実例で評価することになります。
ニューラルネットワークが簡単に(第26部):強化学習 ニューラルネットワークが簡単に(第26部):強化学習
機械学習の手法の研究を続けます。今回からは、もう1つの大きなテーマである「強化学習」を始めます。この方法では、モデルは問題を解決するためのある種の戦略を設定することができます。この強化学習の特性は、取引戦略を構築する上で新たな地平を切り開くものと期待されます。
一からの取引エキスパートアドバイザーの開発(第28部):未来に向かって(III) 一からの取引エキスパートアドバイザーの開発(第28部):未来に向かって(III)
私たちの発注システムが対応できていないタスクがまだ1つありますが、最終的に解決する予定です。MetaTrader 5は、注文値の作成と修正を可能にするチケットのシステムを備えています。アイデアは、同じチケットシステムをより高速かつ効率的にするエキスパートアドバイザー(EA)を持つことです。