IB証券TWSのAPIドミトリーFAQ:実装メモ

こちらはインタラクティブブローカーズのAPI情報、Dmitry's TWS API FAQを日本語に訳したものです。元のウェブページの量が多すぎて閲覧しにくい&元サイトを翻訳にかけるとPCが固まるため、備忘録用に章ごとに分けつつ、できる範囲で変な訳を修正して保存しています。 

目次

[Q] 指定された契約の買値/売値スプレッドを取得するにはどうすればよいですか?

[A]オンラインで表示/返信 (#46694)

2021 年 3 月 13 日に追加

最近それに取り組んでいたので、回答の初稿を載せてみます。

[Q] オプションレッグのビッド/アスクを取得するにはどうすればよいですか?

[A] 今のところ3つの方法が見つかりました。私にとって機能するのは 1 つだけですが、ここでは 3 つすべてについて説明します。

1-of-3: client.reqTickByTickData の使用(19003、ContractSamples.USStockAtSmart()、"BidAsk"、0、true);

この記事を読む: TWS API v9.72+: ティックごとのデータ

特に、入札/売値を提供するIBApi::EWrapper::tickByTickBidAskについて読んでください。

ここでの問題は、同時サブスクリプションが 3 つしか許可されていないことです。これは、1 ~ 2 つの楽器をトレーニングしている人には機能するかもしれませんが、同時により多くの契約の入札/要求を取得するためのより一般的な方法を見つけたかったのです。

2-of-3: EClient.reqMarketDepth  (Java、C++、Python では reqMktDepth) を使用します。次の 2 つのドキュメントを参照してください。

TWS API v9.72+: マーケットデプス (レベル II)

TWS API v9.72+: EClient クラス リファレンス

IB はドキュメントの中で次のように述べています。

API v974 およびTWS v974以降では、 TWS BookTrader の表示と同様に、IBApi.EClient.reqMarketDepthリクエスト をスマート ルーティングして、利用可能なすべての取引所から集約データを受信できるようになりました。

(引用終わり)

そして、常に特定の取引所でのみ取引される契約を取引している場合を除き、この「集約データ」が適切な買値/売値を取得する唯一の正しい方法であるという結論に達しました。したがって、特定の取引所からデータを集約する必要はありません。たくさんのやりとり。Contract.Exchange を SMART に設定し、「isSmartDepth」引数を true に設定して「reqMarketDepth」を使用すると、さらにサブスクリプションが必要であるというエラーが発生します。私のデータサブスクリプションには、「IEX交換」のための無料のものを除いて、レベルIIはありませんでした。Contract.Exchange = "IEX" を設定し、"isSmartDepth" 引数を false に設定しようとすると、データの取得が開始されますが、たとえば "IBM" 契約の場合、静かな低ボラティリティの日には買値/売値が変動することに気付きました ( TWS では約 $0.02 と表示されます)、多くの場合、IB API によってはるかに大きな数字として報告されます (たとえば、予想 $2.45 対 $0.02 – 以下のスクリーンショットを参照)。IB サポートは、TWS ビッド/アスクで表示されるもの (さまざまな取引所のリスト付き) は、サブスクリプションなしでは API 経由でアクセスできないが、TWS ウィンドウでは「人間の肉眼」で無料でアクセスできることを確認しました (OCR を使用する時期が来ました!-) ))。

以下は、2021 年 2 月 8 日午後 2 時 47 分頃、IB API が 2.45 ドルを返し、TWS が入札/売値 = 0.02 ドルの集計データを表示した場合の例です。

IEX ビッドが 121.0、IEX アスクが 123.45 であることがわかります。したがって、「IEX のみ」バージョンによるスプレッドは 2.45 です。厄介で役に立たない!

「reqTickByTickData」に SMART を使用したい場合は、この契約が取引されるすべての取引所のレベル II サブスクリプションが必要になります。

すべての金額を確認するには、 interactivebrokers.comにログイン -> アカウント管理 -> 設定 -> ユーザー設定 -> マーケット データ サブスクリプション ->

「北米: IEX 帳簿の深さ – トレーダー ワークステーション – 手数料免除」が表示されます。

メモと一緒に:

IEX 交換書籍サービスの深さ。NYSE (ネットワーク A/CTA)、AMEX (ネットワーク B/CTA)、NASDAQ (ネットワーク C/UTP)、または米国株式およびオプションのアドオン ストリーミング バンドルへの事前のサブスクリプションが必要です。

(引用終わり)

次に、[現在の GFIS サブスクリプション] -> [歯車アイコンの設定] -> [北米] (例) -> [レベル II (ディープ ブック)] をクリックします。

そして、価格のリストが表示されます。

3-of-3: リアルタイムのバーと「ティック」を使用した貧乏人買い値

次のいずれかの方法で 2 つのリアルタイム 5 秒バー ストリームを購読する場合:

  a) 「keepUpToDate」を true に設定したIBApi.EClient.reqHistoricalData リクエスト( 「TWS API v9.72+: 履歴バー データ」も参照)

    または

  b) IBApi.EClient.reqRealTimeBarsリクエスト ( TWS API v9.72+: 履歴バー データ も参照)

そして、「何を表示するか」を 1 つのリクエストでは「BID」に、別のリクエストでは「ASK」に指定すると、IB API は数秒ごと (平均 3.5 秒ごと) に 5 秒のバー更新と各ストリームの「バー」でコールバックします。 「close」価格は最新の買値と買値を表します。唯一の問題は、これら 2 つのストリームが 2 つのイベント ストリーム (時間的に分離されている) を表していることです。負の計算されたbid_askスプレッドを除外し、入札更新と売値更新が500ミリ秒以内の距離にある場合にのみ入札_askスプレッドを計算します。その結果、同じ「IBM」ティッカーで(取引日全体を通して)平均して3.5秒ごとに計算されたbid_ask値が得られました。これは私にとっては十分です 🙂

注意 #1: この方法は、利用可能な 100 回線のうちの「1 回線」としてのみカウントされるため、理論的には、データ ブースターやレベルを購入せずに 100 個の bid_ask スプレッド (価格更新用にサンプリングされた「リアルタイム ティック」を含む) を取得できます。 -II サブスクリプション。

注 #2: はい、「何を表示するか」タイプ「BID_ASK」があります (「履歴データのタイプ」を参照) が、現在の最新の買値と買値の即時スナップショットは提供されません。代わりに、次のものが得られます。

bar.open = "時間平均入札"、bar.high = "最大売値" (役に立たない)、bar.low = "最小買値" (役に立たない)、および bar.close = "時間平均買値"。5 秒足の「時間平均」値が上記の方法よりも優れているかどうかはわかりません。並べて確認してみますが、私の推測では、どちらのアプローチでも同様の品質の出力が得られるでしょう。 。

この方法が、動きの速い市場にどれだけうまく対応できるかはわかりません。実際の状況についてかなりランダムな推定値が得られると思います。ただし、常に何らかの安全係数を使用できます (たとえば、計算された bid_ask スプレッド値を使用し、念のため 2.0 を乗算します)。また、スプレッド値が現在のボラティリティとどのように相関するかを確認することも興味深いでしょう。ボラティリティの高い時期には、価格が急騰したり、買値/買値が急騰したりする可能性がありますが、高いボラティリティの測定値はほぼ横ばいの高値を示しており、これを使用して買値/売値の最大値を推定する(および/または「安全性」を調整する)ことができます。係数」を設定し、市場が狂ったときに少し高くします:)。

私の記憶が正しければ (4 番目のオプションとして) 15 分遅延の無料の bid_ask ストリームがありますが、15 分の遅延は少し遠すぎるため、そのオプションについては調べていません。

乾杯、

ドミトリー・シェフコプリアス

ps: ここでは、bid_ask 計算のプロトタイプを作成するためにすべての受信バーで使用した関数を示します。この部分を「メタ言語」と考えてください。

   public void on_historical_bar_try_to_calculate_bid_ask_spread(

           Bar bar,

           RequestHistoricalData request) {

       // Check we have both requests in place (not nulls)

       if (request_historical_data_bid == null) {

           logger.debug("request_historical_data_bid == null, nothing to do yet…");

           return;

       }

       if (request_historical_data_ask == null) {

           logger.debug("request_historical_data_ask == null, nothing to do yet…");

           return;

       }

     

       // Both bid / ask "real time" bars requests are present! We can calculate bid/ask spread estimate.

       // Let's extract most recent bars from 2 streams:

       Bar bid_bar = request_historical_data_bid.most_recent_bar_received;

       Bar ask_bar = request_historical_data_ask.most_recent_bar_received;

       if (bid_bar == null) {

           logger.debug("bid_bar == null, nothing to do yet…");

           return;

       }

       if (ask_bar == null) {

           logger.debug("ask_bar == null, nothing to do yet…");

           return;

       }

       // Check how far in time they are from each other

       long bars_received_time_delta_ms = request_historical_data_bid.most_recent_bar_received_time.get_delta_ms(request_historical_data_ask.most_recent_bar_received_time);

       // Filter out updates with more than 500ms distance

       if (Math.abs(bars_received_time_delta_ms) > 500) {

           return;

       }

       // Both bid/ask bars are present and close enough, let's calculate the bid/ask spread

       double bid_ask_spread = ask_bar.close() – bid_bar.close();

       // Filter out some obvious BS

       if (bid_ask_spread <= 0) {

           return;

       }

       logger.info("Calculated synthetic poor man's bid_ask_spread: "

               + Aid.math_round(bid_ask_spread, 2)

               + " bars_received_time_delta_ms: " + bars_received_time_delta_ms);

   }

[Q] OCAグループを閉じるにはどうすればよいですか?

[A]オンラインで閲覧・返信

2021 年 2 月 22 日に追加

Nick:逆指値注文を成行注文に変更することもできます。これはすべての注文タイプで機能するとは限らないため、自分のシナリオで試してみる必要があります。

[素敵でエレガントなソリューション!]

ds-avatar: TWS は、OCA (one-cancels-all) グループ ID を子ストップロス注文に自動的に割り当てます。これにより、複数の子注文が送信された場合に 1 つの子注文のみの実行が実装されます。これを手動の市場撤退注文に使用して、その実行によって子注文がキャンセルされるようにすることができます。

[Q] 戦略を特定するための順序フィールドは? (clientID 対 orderRef 対 permID)

同じアカウント/サブアカウントで複数の戦略を実行しています。

誰がどの注文をしたのかを区別したい。

Order クラスに、カスタム値を割り当てることができ、その値を永続化して、後で誰が注文したかを識別できるフィールドはありますか?

誰かがorderRef フィールドを使用することを提案しました。

同様の質問: Corneliu Maftuleac  corneliu.maftuleac@gmail.comオンラインで表示/返信 (#46716) 

注文の orderRef フィールドを使用して、注文が特定の戦略に属していることをマークします。

ただし、フレックス クエリを使用して注文のリストを取得する場合、OrderReference フィールドは常に空になります。

ドキュメントに指定されているとおり: 注文チケットでユーザーが定義した注文参照番号。

注文参照を取得する方法はありますか?

[A]オンラインで閲覧・返信

2021 年 2 月 22 日に追加

OrderRef がありますが、セッションをまたがって保持されない可能性があるため、ニーズを満たしていることを確認する必要があります。

ニックの「セッション」とは次のような意味でした。

外国為替を除いて、市場は 24 時間 365 日継続的に取引されるのではなく、1 日の一部だけしか開いていません。

一般的な考え方は、市場は特定の時間に開き、その後特定の時間に閉じる、これが 1 つの取引セッションであるということです。翌日の取引は別のセッションとなります。

金融商品が異なれば、セッションの開始と終了に関するルールも異なります。主要な先物取引所の 1 つのセッションは暦日にわたっており、ある日の夕方に始まり、真夜中を過ぎて午後または翌日まで続きます。取引は月曜日の夜に行われる可能性がありますが、火曜日の取引日としてカウントされるため、頭がおかしくなるかもしれません。

OrderRef に戻ると、注文が行われたときと同じセッションで約定する場合はフィールドが返されるが、注文が後続のセッションで約定される場合は空になることが観察されています。

Mark Colling 氏も OrderRef を提案しました。

注文参照フィールドに保存されている取引参照を使用していますが、通常は問題なく機能します。注文 ID、注文参照、内部追跡 ID を追跡すると、すべてをつなぎ合わせることができるはずです。

私が経験したのは、ポジションレポートは何分も遅れており、約定レポートは任意の順序で到着しますが、注文参照は安定しているようです。

ds-avatar による回答:

OrderRef は、最新のセッションのレポートのみに含まれます。回避策: 日次レポートをメールで送信し、収集して照合するようにシステムを設定します。

[ベストアンサー by praditik]

permIDを使用し 、それをローカルに保存して戦略マッピングを識別しました。セッションや日をまたいでシームレスに機能します。したがって、他の誰もがすでに述べたように、プログラム内でローカルマッピングでpermID を使用する と、うまくいくはずだと思います。

解決:

はい、残念ながら OrderRef は最終的には消えてしまいますが、レポートにはアカウント固有の識別子である order.permID フィールドも含まれており、永久に存在するはずです。

したがって、すべてのordersRef値と、注文に割り当てられた対応するpermIDをローカルで追跡できます。したがって、数か月後、IB からレポートを取得すると、ローカル テーブル (orderRef <–> permId) を検索することによって、元の orderRef 値を復元できるようになります。私も同意します – IB のレポートは独立したものであるべきであり、既存のフィールドの一部を削除する理由がわかりません (存在する場合は、永久に存在するはずです)。しかし、それは事実です。うまくいくかどうか教えてください。レポートに permID が表示されますか?

Corneliu Maftuleac: – はい、レポートに permID が表示されます。

[Q] 接続喪失の検出

[A]オンラインで閲覧・返信

2021 年 2 月 4 日に追加

ユージーン

はい、2015 年 9 月頃にこのスレッドで非常によく似たトピックが議論されました (件名: 非同期 EClient::eConnect() は必要ですか?)。その結論は、TWS API に接続しただけで何も送信しないと、問題が発生する可能性があるというものでした。それを迅速に検出する時間が必要です (場合によっては、TWS 側で接続が古くなり、再起動しないと (または 30 ~ 40 分ほどかかると)、同じクライアント ID を使用して TWS に再接続できなくなります)。

これに対する解決策は、「十分にノイズの多い」ものにサブスクライブすることで、TWS サイトがクライアント アプリへの確立された TCP 接続を使用しようとすると同時に、クライアントから TWS API に単純なもの (reqCurrentTime() など) を毎秒要求し続けることになります。 (TWS は、リモート IB サーバーに迷惑をかけたり問い合わせたりすることなく、独自に応答します。そのため、煩わしくても安全です:) これら 2 つの「ストリーム」が、あなたが探している「ハートビート」になります。

それが役に立てば幸い、

ドミトリー

こんにちは、カートさん

午前1時30分の私の返信では、「TWS <==> IB 」ではなく「 client <==> TWS 」検出に落ちたようです

ユージーンが述べたように、APIクライアントは注文を送信しようとしたとき(またはTWSへの他のAPI呼び出しを実行したとき)にのみ接続損失を検出します。これは、私のクライアントがTWSボックス以外で実行されていたときに上記のスレッドで約1年前に観察した問題とまったく同じです。したがって、それを軽減するには (そして TWS への接続が失われたことを API クライアントがより早く認識できるようにするには)、クライアントは TWS と通信することを試みる必要があります。また、TWS は、クライアントに何かを配信できなかった場合、内部接続記述テーブルをより迅速にクリアします。そのため、時間を尋ねる (クライアント -> TWS) ことと、ティッカーをサブスクライブする (TWS -> クライアント) ことで、両方向をくすぐることを提案します。

「 TWS <==> IB 接続が失われました」に関しては、「client <==> TWS 」接続は正常です (簡単にするために、API クライアントと TWS が同じホスト上にあるとします)。 TWS には確かに何らかのメカニズム (ハートビートなど) があります。 TWSで何もサブスクライブしていない場合は、10秒ごとにリモートIBホスト(私の場合はcdc1.ibllc.com、~/Jts/jts.iniにもあります)が次のようなコンテンツ(切り捨てられた)を含むパケットをプッシュしていることがわかります。パケットペイロード): "FIX.4.1.9=00014.35=1.112=farm.10=217" および

「FIX.4.1.9=00027.35=0.112=FixTestRequest195.10」

次に、TWS は次のような FIX プロトコル関連の内容を IB に報告します。

「FIXCOMP.9=70.x」

TWS <==> IB 接続」が失われると、API クライアントは TWS によって直ちに通知されます。したがって、幸いなことに、TWS が IB との接続の認識についてこれまで共有されていなかった情報をクライアント アプリと「共有」するための新しい魔法の杖を発明する必要はありません。このロジックはすでに存在しています。私の TWS は 30 秒以内に接続が失われたと報告し、ネットワークが復元されると 5 ~ 10 秒以内に回復します。

真夜中の発言でわかりにくくてごめんなさい 🙂

ありがとう、

ドミトリー

[Q] 取引所で全シンボルのリストを取得しますか?

[A]オンラインで表示/返信 (#46323)

2021 年 1 月 29 日に追加

NASDAQ には API があり、すべてのシンボルとその最終価格のリストを JSON として提供します。

https://api.nasdaq.com/api/screener/stocks?tableonly=true&limit=25&offset=0&download=true

[Q] 株式/オプションの標準偏差を取得しますか?

TWS で簡単なオプション分析グラフを取得する方法はありますか?

株価の標準偏差の計算方法をご存知ですか?

目標は、株式/オプションの SD を計算するために必要なすべてのデータを API 経由で取得することです。

[A]オンラインで表示/返信 (#44329)

2020 年 10 月 3 日に追加

reqHistoricalData の HISTORICAL_VOLATILITY を見てください。

https://interactivebrokers.github.io/tws-api/historyal_bars.html#hd_what_to_show

- また

TWS では、オプションを右クリックしてそのパフォーマンス プロファイルを尋ねることができます。これはほぼ同じウィンドウです。

ID 104 と 106 の株式契約で reqMktData を使用すると、特定の株式の年換算の HV と IV が得られます。

ID 106 の特定のオプション契約の年換算 IV を取得できますが、HV は取得できません。

30 ティックを超える場合は、IB がウィンドウ 30 の Garman Klass 式を使用していると思われるため、HV を自分で計算することもできます。しかし、他のボラティリティ式を使用することもできると思います。

もちろん、特定の日付の正確な範囲を取得するには、ボラティリティを期間に合わせて調整する必要があります。15 営業日にわたるボラティリティが必要な場合: VOL / ((15/252) ** 0.5)

お役に立てれば

[Q] APIから切断されたTWSを検出するにはどうすればよいですか?

2020年5月20日水曜日午後2時45分、スプレッド・ヘンドラーは次のように書きました。

私は TWS 978.1 と最新の TWS API 9.79.01 (できれば最新の API バージョン) を使用しています。

TWS が API から切断された場合 (残念なことに、TWS978 が頻繁に突然シャットダウンしてしまいます)、API 経由でエラー メッセージは受け取りません。

[A]  by rwk、オンラインで表示/返信 (#44515)

2020 年 8 月 4 日に追加

何か問題が発生したことを知らせる切断メッセージに依存するのは危険であるように思えます。接続が良好であっても、見積もりを取得できない、または注文できない可能性があります。私がやっているのは、アクティブであるべきだとわかっているインデックス ETF などの契約を監視することです。データがない状態が 20 秒間続くなど、一定の時間が経過した後、アラーム音を鳴らして調査します。

[Q] 「価値がない」とはどのような価値ですか?

[A]  by Kurt ( src )

IB では、「値なし」を意味する値の使用に一貫性がありません。INT_MAX または DOUBLE_MAX の場合もあれば、0 の場合もあり、-1 の場合もあり、-0.99 の場合もあります。

ヒストリカルバーボリュームフィールドは TRADES に対してのみ設定され、BID、ASK、MIDPOINT、BID_ASK、OPTION_IMPLIED_VOLATILITY、または HISTORICAL_VOLATILITY に対しては設定されません。したがって、TRADES を提供しない商品 (FX など) には利用可能なボリュームがありません。

おそらく、特定のパターンに従わず、文書化されていない方法で、さまざまな楽器で省略されているものが他にもたくさんあるでしょう。得られるものだけを得ることができます。様子がおかしくても心配しないでください。それは、IB で発生する問題の中で最も少ないものです。

過去のデータでは、バー内の未使用のフィールドが 0 になる場合もあれば、-1 になる場合もあることに確かに気づきました。確かにそれに関する文書はありません。

–カート

[Q] ID / nextValidId を処理するためのベスト プラクティスは何ですか?

[A] edbar@exmsft より。この スレッドから

ID をハードドライブに保存します。

次に、TWS を起動するときに、TWS が送信する nextID をチェックして、どれがどれであるかを確認します。

の方が大きいです。

保存されている ID が TWS 番号より大きい場合は、自分の ID を使用します。

その後、ID 番号を増やすたびに、ハードドライブのバックアップを更新します。

いつでも TWS CONFIG API 画面に移動して、API ID 番号をリセットできます。

–エド

[A2]  btw12342001 (同じスレッド)

orderIdをtickerIdに使用するべきではないと思います。reqAnythingData に指定する番号は orderId ではなく、コールバックでどのようなデータが来るかを知るためのものです。複数のデータ シンボルをサブスクライブする可能性があります。orderId と混同される理由はまだ説明されていません

2002 年の質問に答える必要はないと思います 🙂

[A3]  by Kurt (同じスレッド)

ここで多くの人が nextValidId() を使用するだけでは機能しないと報告しています。

十分な。問題なくやっていたので覚えていないかもしれませんが、

詳細はわかりますが、(ディスク上に)記録しておくのが一般的だと思います。

最大の注文 ID を使用し、その値と返された値の大きい方を使用します。

起動時に nextValidId によって増加し、そこから増加します。確認してもいい

アーカイブ。この質問が最後に行われたのは 2 か月以内です

信じる。

reqMktData などに関しては、それぞれに独自の ID スペースがありますが、独自の

正気であれば、おそらくそれらを一意に保ちたいと思うでしょう。すべてのリクエストIDを保持します

別のスキームを使用した placeOrder を *除いて * ユニークです。使用する

一意のリクエスト ID により、受信リクエストエラーのルーティングが容易になります。

-カート

[A4] リチャード L キング著rlking@aultan.comオンラインで表示/返信 (#44680)  

2020 年 10 月 10 日に追加

API によって、ID を使用するさまざまなリクエストに対して異なる範囲の ID を使用するという要件はありません (唯一のルールは、注文 ID を絶対に減少させてはいけないということです。ただし、TWS 経由で特定の clientID の注文 ID をリセットできる点は異なります)。さらに、市場データのリクエスト、履歴データのリクエスト、注文などに同時に同じ ID を使用することを妨げるものはありません。

 

ご覧のとおり、これによりエラー コールバックに潜在的な問題が発生します。

 

これに対処する 1 つの方法は、独自の範囲を定義することです。たとえば、市場データ リクエストの場合は 0 ~ 1023、契約詳細リクエストの場合は 1024 ~ 2047 などです。もちろん、範囲の終わりに達したときに何が起こるかを考える必要があります。これに対処する方法はたくさんあります。そのような考慮事項は、範囲をどれくらいの大きさにするかを決定する際の指針となります。たとえば、契約の詳細リクエストはかなり早く完了するため、ほぼ確実に、たとえば 1000 個の ID の範囲で問題を回避し、最後に到達したら最初に戻るだけで済む可能性があります。最初のリクエストが存在しない可能性があります。次の 999 件のリクエストを行うまでに完了するということはリモートです。ただし、私は個人的にはリスクを負いません。使用された ID と無料の ID を追跡するために、ある種のデータ構造を使用します。

 

これを行うと、非負の ID を含むエラー メッセージについて、そのメッセージがどのタイプのリクエストに関連しているか、さらには、たとえばテーブルのインデックス付けに ID を使用する場合など、正確にどのリクエストであるかを判断するのが簡単になります。リクエストタイプごとに。

 

このような仕組みを使っています。特に、注文 ID には 0x10000000 から 0x7FFFFFFF を使用します。この範囲が広いということは、一生のうちに注文 ID が不足することはないだろう (注文 ID は 1,879,048,191 個あります!) ため、注文 ID のリセット メカニズムを使用する必要がありません。また、この範囲内で、単一注文と括弧内のエントリー注文の ID が 0 または 5 で終わり、括弧内のストップロス注文が 1 または 6 で終わり、括弧内のテイクプロフィット注文が 2 または 7 で終わることを確認します。これは次のとおりです。ログファイルを確認するときに注文の役割を識別しやすくするためです。

 

この種のスキームは、CompletableFutures の使用と完全に互換性がある必要があります。

 

リチャード

[Q] 接続が失われた後、同期するためにすべてのオープン注文とポジションのリストが必要ですか?

[A]  by src 

reqAccountUpdates() メソッドを呼び出すと、位置が updatePortfolio() イベントで報告されます。イベントは位置ごとに 1 回発生します。その後、変化がある場合は発火し、変化がない場合は約 2 分に 1 回発火します。うまくいきます。

[rwk]

死刑執行を要求することも検討してみてはいかがでしょうか。場合によっては注文をオープンしたり、

実行レポート (またはその両方) は、IB の誤機能または

何でも。情報は多ければ多いほど良いので、リクエストすることを意味します

ポジションも良いアイデアです。ポジションはアカウント更新の一部です。

-カート

> reqAccountUpdates() の acctCode パラメータで何を送信すればよいですか?

FA アカウント シナリオがない場合は、null 文字列に設定できます。

-カート

または、アカウント コード UXXXXXX または FXXXXXXに設定できます。

updatePortfolio() のposition パラメータには何を受け取りますか? それは?

ポートフォリオの契約数

はい

[Q] 追跡時間(内部処理)

[A]ドミトリー著

これは、外部から受信するタイムスタンプとは何の関係もありません。すべての内部イベントのローカル タイムスタンプのみを目的としています。十分な解像度として、ミリ秒の解像度を選択します。ローカル時刻は、できる限り頻繁に NTP サーバーからポーリングされた更新によって NTP で維持されます (GPS pps 信号に基づいて独自の Stratum-1 NTP サーバーを構築する必要がありました (詳細については、タイム ドリフトを参照 ))

long get_epoch_ms()

{

    // http://brian.pontarelli.com/2009/01/05/getting-the-current-system-time-in-milliseconds-with-c/

    timeval t;

    gettimeofday(&t, NULL);

    long epoch_ms = (t.tv_sec * 1000) + (t.tv_usec / 1000);

    //std::cout << ";" << t.tv_sec << ";" << t.tv_usec << " or simply epoch_ms: " << epoch_ms << std::endl;

    return epoch_ms;

}


[Q] ライブトレードの構築

関連項目も参照してください: [Q] ある程度正確な累積量を取得するにはどうすればよいですか?

関連項目も参照してください: [Q] NickSize() NickPrice イベントのシーケンスは何ですか?

[A]ドミトリー著

成立した取引のイベントを抽出したい場合 (一部の BID/ASK 移動ノイズではなく、実際に成立した実際の価格/出来高の取引)、IB は相対的なものしか送信しないため、完全に単純ではない可能性があるため、次の考慮事項に従う必要があります。取引に関する絶対的な自己完結型の個別メッセージの代わりに「違い」を表示します。ウォームアップするには、以下をお読みください: [Q] lastSize=0 の場合があります。なんと?

ここで、Dmitry が使用する取引を取得するための実装アルゴリズムは次のとおりです。

– MyContract クラス内に取引用のコンテナがあります

– すべての tinyPrice()、tickSize() イベントは、ewrapper によってリクエスト オブジェクト (RequestMktData) にルーティングされます。このリクエスト オブジェクトは MyContract クラス インスタンスに関連付けられており、このインスタンスには、受信ティックを処理するための tinyPrice()、tickSize() メソッドがあります。

– 次に、MyContract クラス内で次のようにします。

void MyContract::tickPrice(Account *account, long epoch_ms, TickerId tickerId, TickType tickType, double price, int canAutoExecute) {

    LOG(INFO) << "MyContract::tickPrice";

    // forward raw tick to subscribed algos (if any)

    for (std::vector<AlgoBase*>::iterator ialgo = subscribed_algos.begin(); ialgo != subscribed_algos.end(); ialgo++) {

        (*ialgo)->tickPrice(account, this, epoch_ms, tickerId, tickType, price);

    }

    // analyze if GotTrade()

    if (tickType == LAST) {

        // we got new trade, but we have to wait for TickSize() call to

        // complete the Trade obj (and then will call GotTrade(trade) to pass

        // complete Trade object to all subscribers)

        this->tradesPerAccountMap[account_as_key].push_back(new Trade(account, epoch_ms, tickerId, price));

    }

. . .

}

void MyContract::tickSize(Account *account, long epoch_ms, TickerId tickerId, TickType tickType, int size) {

    LOG(INFO) << "MyContract::tickPrice";

   

    // forward raw tick to all subscribers

    for (std::vector<AlgoBase*>::iterator ialgo = subscribed_algos.begin(); ialgo != subscribed_algos.end(); ialgo++) {

        (*ialgo)->tickSize(account, this, epoch_ms, tickerId, tickType, size); // forward tickSize() event to subscribed algos (if any)

    }

        // analyze if GotTrade()

    if (tickType == LAST_SIZE) {

. . .

        // CASE 1 of 3: check if last_trade is in "waiting for size" state (last_trade->size < 0 aka 'uninitialized'))

        if (last_trade->size < 0) {

            // last_trade's size is not yet initialized, means we waited for this tickSize() event

            // to complete the trade obj (and forward it to all subscribers)

            last_trade->size = size;

            last_trade->completion_time_ms = epoch_ms – last_trade->epoch_ms; // we track how long it took us to complete this trade object

            last_trade->is_complete = true;

            // forward complete trade to all subscribers

            gotTrade(last_trade);

            return;

        }

        // CASE 2 of 3: Is it duplicate of last_size tick (same size as last complete trade and within 9ms) => just ignore it

        if (last_trade->expect_dup_ticksize && last_trade->size == size && (epoch_ms – last_trade->epoch_ms) <= 9) {

            last_trade->expect_dup_ticksize = false; // mark last_trade as "got expected duplicate" so next tickSize if

            // happen to arrive within <7-8ms with the same size field would not be treated as duplicate anymore

            // (the 'expect_dup_ticksize' flag allows us to ignore tickSize only once

            // and only for expected ticks (ones that go after "Last" 2 times in a row))

            return;

        }

        // case 3 of 3: It is normal LAST_SIZE tick telling us about new trade with the same price as before! We got new trade!

        Trade * new_trade = new Trade(account, epoch_ms, tickerId, last_trade->price, size, true, 0, false);

        ptrades->push_back(new_trade);

        // forward complete trade to all subscribers

        gotTrade(new_trade);

        return;

    }

}

【Q】ライブバーの構築

[A]

https://groups.io/g/twsapi/topic/4046604

https://groups.io/g/twsapi/topic/4046154

[Q] なぜ 2 つの同一の checkSize() コールバックが取得されるのですか?

[A]リチャード・L・キングが説明

日付: 土曜日、2011 年 2 月 5 日 00:47:45 -0000

件名: RE: [TWS API] Re: NickSize(): LAST_SIZE と VOLUME の順序

おそらく、この主題に少し光を当てて、それが何であるかを説明できるかもしれません

ここで実際に起こっていることとその理由。

API の初期の頃、TICK_PRICE プロトコル メッセージ (つまり、

コールバック関数/イベントではなく、それ自体) のバージョン番号は 1 で、

価格フィールドはありますが、サイズフィールドはありません。

そのため、当時はすべての価格とすべてのサイズが TICK_PRICE メッセージで送信されていました。

Tick_SIZE メッセージ内。IB が使用するサンプリング メカニズムに留意してください。

前回のサンプリング中に変更された値のみを送信します。

間隔。価格が変更された場合は、事前に TICK_PRICE メッセージが送信されます。

対応する TICK_SIZE メッセージ。しかし、このアプローチには問題があり、

TICK_SIZE メッセージはサイズが変更された場合にのみ送信されるためです。したがって

TICK_PRICE メッセージがいつ到着したかをクライアントが知る方法はありませんでした。

対応するサイズが前のサイズと同じかどうか (

この場合、TICK_SIZE メッセージはありません)、またはそれも変更されたかどうか、

Tick_SIZE メッセージが続きます。

この問題を解決するために、IB は TICK_PRICE メッセージのバージョン 2 を導入しました。

API v760 ベータ版 (これの私のコピーの日付は 2004 年 2 月 15 日です)。これにはサイズも含まれていました

フィールド、そして今では TICK_PRICE フィールドが送信されるたびに (つまり、

サンプリング間隔中の価格が変更されました)、サイズを含めることができます

サイズ自体が変わったかどうか。TICK_PRICE メッセージは次のようになります。

checkPrice() コールバックとその後に続く tinySize コールバックの両方を生成します。これ

つまり、クライアントは、tickPrice() コールバックを受け取ったときに、それを簡単に行うことができました。

価格を覚えておくだけで済み、後続のtickSize()は

次のtickPrice()まで暗黙的にその価格に関連付けられます。

しかし、今度は別の問題が発生しました。を使用していたクライアントは、

クライアントのバージョンが 15 未満の古いバージョンの API は機能しません。

バージョン 2 メッセージを理解できるため、TWS はバージョン 1 を送信し続けることになります。

これらのクライアントに TICK_PRICE メッセージを送信します。しかし、これは、tickSize() が

tinyPrice() コールバックに続くコールバックは生成されないため、

クライアントは完全な情報を持っていないでしょう。これを修正するには、

TICK_PRICE メッセージに加えて、IB は TICK_SIZE メッセージも送信することにしました。

TICK_PRICE メッセージと同じサイズ。したがって、バージョン 15 未満のクライアント

これで完全な情報が得られます。

愚かなことに、IB は追加の TICK_SIZE のみを送信すべきでした。

クライアントのバージョンは 15 未満でしたが、実際にはすべてのクライアントに送信されました。

もちろん今もそうしています。それで今、私たちはこの愚かな状況に陥っています

ここで、TICK_PRICE メッセージが送信されるたびに、冗長な TICK_SIZE メッセージが送信されます。

その結果、tickPrice() コールバックの直後に 2 つの同一のコールバックが続きます

tinySize() コールバック。

では、なぜ IB はこれを修正しないのでしょうか? まあ、よくわかりません。彼らはこう思っているのかもしれない

それは重要ではありません。たとえば、データを監視している人がいるからです。

画面上では決して気付かないでしょう。それは単に私たちが物事を集計するのが好きだからです

そして、それが私たちをイライラさせる累積ボリュームの数字と比較してください(そして

もちろん、それはただの愚かだからです!)。

何が起こっているのかを理解すれば、それをコーディングするのは簡単です。

マイクがすでに以下で指摘しているように。

この件について IB に苦情を申し立て、修正するよう説得したい場合は、次のようにしてください。

ぜひ試してみてください。しかし、彼らが興味を示すかどうかは非常に疑問です

全然。彼らは過去7年間そうしていませんでした(そして結局のところ彼ら自身も

TWS でコードを丸める必要があったに違いありません)。

実際、ここでの本当の問題は問題そのものではなく、

非常に多くの人がそれを発見し、心配するのに非常に多くの時間を費やしているという事実

そして回避策を考え出すのです。しかし、それは非常に多くの側面に当てはまります

APIの…

リチャード

[A] Richard L Kingによってさらに詳しく説明されています(ここにあります)

2015 年 6 月 9 日に追加

ここで何が起こっているかを要約しましょう:

1. 価格が変更されると、TWS は価格とサイズの両方を含む 1 つのメッセージをクライアント アプリケーションに送信します。

2. IB の API コードは、個別の tinyPrice コールバックと TickSize コールバックを作成します (後者は前者の直後にあることに注意してください。これは API コードで簡単に確認できます。

3. その後、IB のサーバーはサイズを再度送信し、API は別の同一の TickSize コールバックを実行します (この理由は、6 月 2 日の rholowczak の投稿にリンクされている FAQ への私の寄稿で説明されています。これは青で強調表示されている部分です:それをよく読んでください)。

4. *同じ*価格で*異なる*サイズの取引があるたびに、別のtickSizeコールバックが作成されます。

5. *同じ*価格と*同じ*サイズで取引がある場合、tickSizeコールバックは行われません。

このことから、tickPrice コールバックごとに *少なくとも 2 つの tinySize コールバックが存在することがすぐに推測できます。価格は取引ごとに変わらないため、通常はさらに多くなります。

ちなみに、前回の投稿で言及した「ブランクタイム」をいじる必要はありません。tinyPrice コールバックを受け取った場合は、価格を記録するだけです。次のコールバックは *常に * ティックサイズ (API コードをチェックして、これが正しいことを確認してください) なので、サイズを記録し、アプリケーション コードを呼び出して、価格とサイズの合計を処理します。その後、tickSize コールバックを取得するたびに、サイズが最後に記録したサイズと同じである場合は、それを無視します (上記 3 で説明した重複の tinySize になるため)。それ以外の場合は、アプリケーション コードを呼び出して、価格とサイズの合計を処理します。ここで、価格は最新のtickPriceコールバックに記録された価格です。

上記の 5. で述べたことにもかかわらず、サイズが前のサイズと同じで価格が変更されていない場合に、tickSize が発生する * 場合が * あることを指摘する価値があるかもしれません。ただし、それはまれです。データ フィードのおおよその性質を考慮すると、それらを検出するために物事を複雑にする価値はありません。とはいえ、私自身の API コードは状況をいくらか複雑にしますが、それによって何が得られるのかはわかりません。したがって、誰かが本当に興味を持っていない限り、私はこれらの余分なシワについてわざわざ説明しません。

関連する項目も参照してください:   [Q] ライブ取引の構築

[Q] 単一のアカウントで 100 を超えるシンボルの市場データを受信するための優れたアルゴリズムを誰かが提案してもらえますか?

[A] ジェイソン・サップ著

私は紙取引の 1 つを利用する「ラウンドロビン」タイプのアルゴリズムを使用しています。

アカウントを使用して、約 1000 個のシンボルの累積ボリュームを取得します。私もそうではありません

累積ボリューム番号が数分ずれているかどうかが心配なので、これは

私にとっては役に立ちます。私のやり方は次のとおりです。

-最初の 90 シンボルに対して reqMktData (累積ボリュームを含む) を呼び出します。

私のリスト (reqMktData を 1 秒あたり 30 回以上呼び出さないようにしてください。

少なくとも 30 が魔法の数字だったと思いますが、この制限はもうなくなるかもしれません

場所)。

- 10 秒待ちます (90 シンボルの最後のシンボルに対して reqMktData を呼び出した後)。

-これらのシンボルすべてに対して cancelMktData を呼び出します。

-私のリストから次の 90 個のシンボルを取得します。

-最初からやり直してください。

90 個のシンボルを使用した理由は、時々 1 つまたは 2 つの市場列があったためです。

私の紙トレーダーTWSが使用しています。

ジェイソン

———————- 代替案も ———————————

ここから

Yahoo Financial の CSV フィードを使用しています。1 つのファイル内で複数のシンボルをリクエストできます。

単一のリクエストで各シンボルの価格データのスナップショットを迅速に取得できます。のために

たとえば、最後の価格、毎日の高値、毎日の安値、終値、出来高をリクエストするには

2000 個のシンボルがあると、Yahoo からその情報を取得するのに 10 秒ほどかかります。

私は特に朝、株式をスキャンするときにこれを使用します。これ

自分のやり方でラウンドロビンを試みるよりも効率的、迅速、信頼性が高い

TWS リクエストを通じて、TWS のリクエスト制限に対処します。

アカウント。

… ブラント・ハーン著

[Q] データリンクがドロップします。フィードは消えます。本格的なソフトウェアはそれを処理する必要があります。どうやって?

[A]  Russ Herrold による実装アイデア

実際問題として、何らかのインジケーターをサブスクライブすることで、

継続的に更新されるだけでなく、よりゆっくりとしたシンボル、

常に何らかの値がその秒間に表示されます。

リンクはライブです — ES などを見てください 😉

[Q] リクエスト/レスポンス/エラーのアーキテクチャについての考え方は?

[A] by Kurt (このスレッドから: C++ アーキテクチャの質問) 

それを行う方法は何百もあります。私は「理想」を信じていません。あなただけでなく他の人にとっても役立つかもしれないので、ここにコードを投稿します。(このコードから、私が使用しているリクエスト/レスポンス/エラー アーキテクチャの大部分を再現できるでしょう。)

リクエストごとにインスタンスを使用してリクエスト追跡クラスを実装しました。デフォルトの動作では、コンストラクターがリクエストを送信しますが、リクエストを作成して送信を延期することもできます。このクラスは、レイテンシーの追跡、ログ記録、リクエストに対する応答とエラーの照合などの便利な機能を多数提供します。

この目的のために、コントラクトベースのクラスのサブクラス ActiveRequestWithContract を持つ ActiveRequest クラスを用意し、ActiveRequest によって提供される汎用ログ機能に追加情報を追加します。次に、ActiveRequest または ActiveRequestWithContract のサブクラスのいずれかである、IB リクエスト タイプごとに個別のサブクラスをさらに用意します。このレベルでは、適切な TWS API 要求メンバー関数を呼び出して要求を送信およびキャンセルするための実装が提供されます。

私は、目的ごとに、または Objective-C ハンドラーへのディスパッチなど、個別のインターフェイス要件ごとにさらにサブクラス化を使用します。

応答とエラーを照合するために、私は既存の要求追跡オブジェクト、つまり削除されていないオブジェクトのリストを保持します。これは、オブジェクトが送信されたか、応答を受信したか、または応答の完全なセットなどを受信したかどうかとは独立して考慮されます。リクエストの最終クライアントは、該当する場合、レスポンスが完了したときにリクエスト オブジェクトを削除するかどうかを決定できます。

その結果、リクエスト ID で検索できる既存のリクエストのリストが作成されます。これにより、リクエスト ID を参照する着信応答と着信エラーを、適切なリクエスト追跡オブジェクトにルーティングできるようになります。したがって、エラーによりリクエストが中止された場合、リクエスト クライアントに通知できます。

これは最適ではないため、おそらく不十分であり、確かに理想的ではありません。パフォーマンスが問題になる場合は、リクエストのリストを B ツリー、またはハッシュ テーブルにすることもできます。したがって、C++ STL によって提供される連想配列を使用できます。

いずれの場合も、リクエスト追跡実装の大部分は、tickPrice コールバックから完全に削除されます。ただし、特定の IB リクエスト タイプに固有のリクエスト追跡サブクラスごとに、対応する EWrapper メンバーと同じ名前とパラメータを持つメソッド (メンバー関数) があります。関数プロトタイプをコピー&ペーストするだけです。したがって、クラス階層の一部は次のようになります。

    MarketDataRequest : ActiveRequestWithContract : ActiveRequest

そして、私のEWrapperサブクラスにはもちろんこのメンバーがあります

   virtual void tinyPrice( TickerIdtickerId, TickType field, double price, int canAutoExecute);

私のMarketDataRequestクラスにもあります

    virtual void tinyPrice( TickerIdtickerId, TickType field, double price, int canAutoExecute) = 0;

実装は次のレベルのサブクラスに任せられます。このアプローチにより、アプリの詳細が一切含まれていない TWS API への汎用インターフェイスが得られます。

次に、汎用の tinyPrice 実装は、二重リンク リストの線形検索を実行して、ルーティング先のリクエスト オブジェクトを見つけます。これは次のようになります。MyWrapper のスーパークラスは、リクエストをログに記録するだけのデフォルト実装を提供します。その結果、この実装では、ルーティングに失敗したリクエストがログに自動的に表示されます。

void MyWrapper::tickPrice( TickerId tickerId, TickType field, double price, int canAutoExecute)

{

    for (ActiveRequest *req = marketDataReqTracker.Next(); req != &marketDataReqTracker; req = req->Next())

    {

        if (req ->ReqId() == tickerId)

        {

            if (MarketDataRequest *specificReq = dynamic_cast<MarketDataRequest *> (req))

            {

                specificReq ->tickPrice (tickerId, field, price, canAutoExecute);

                return;

            }

        }

    }

   

    inherited::tickPrice (tickerId, field, price, canAutoExecute);  // default logging used when response not routed above

}

これは完全に効率的というわけではありませんが、私の目的には「完全に適切」であり、コンテナー抽象化 (STL など) を使用していない場合でも、必要に応じてアップグレードするのが十分簡単です。

MarketDataReqTracker にはMarketDataRequestオブジェクト のみが確実に含まれる必要が あるため、dynamic_castの使用は厳密には不要ですしたがって、このコードはテンプレートの使用によって恩恵を受けた可能性があります。しかし、それがなくても static_cast は安全であり、パフォーマンスへの影響が問題にならないという理由だけで、私は保守的なことをしただけです。ただし、ダウンキャストが必要なのは、tickPrice メンバーがMarketDataRequestサブクラスに固有であるためです。つまり、上記の説明によれば、EWrapper インターフェイス全体が各リクエスト オブジェクトに確実に含まれていないためです。

一方、エラー処理はこれにある程度似ており、私の EWrapper サブクラスがこの実装を提供しています。

void MyWrapper::error(const int id, const int errorCode, const CString errorString)

{

    (void) error_Route (id, errorCode, errorString);

}

error_Routeは、より賢明で直接的なルーティングのために一連のエラー コードを特別に処理し、それ以外の場合は ReqTracker_error_Route を呼び出します。

ActiveRequest *MyWrapper::error_Route(const int id, const int errorCode, const CString& errorString)

{

    if (errorCode == 505)

        // actual:    "request 2104 error 505 Fatal Error: Unknown message id."

        printf ("generic error %d %s [id=%d]\n", errorCode, errorString.CStr(), id);

    else if (id == kIBNullReqId)

        printf ("generic error %d %s\n", errorCode, errorString.CStr());

    else

        printf ("request %d error %d %s\n", id, errorCode, errorString.CStr());

   

    bool handled = false;

    ActiveRequest *handledBy = NULL;

   

    switch (errorCode)

    {

        // errors specific to Orders

        case 103:    // [from doc]  Duplicate order ID.

        case 104:    // [from doc]  Can't modify a filled order.

        case 105:    // [from doc]  request 45 error 105 Order being modified does not match original order

        case 106:    // [from doc]  Can't transmit order ID:

       

        …

        case 121:    // [from doc]  Invalid BD flag for the order. Check "Destination" and "BD" flag.

        case 122:    // [from doc]  No request tag has been found for order:

        // 123, 124 vague

        case 125:    // [from doc]  Buy price must be the same as the best asking price.

        case 126:    // [from doc]  Sell price must be the same as the best bidding price.

        case 129:    // [from doc]  VWAP orders must be submitted at least three minutes before the start time.

        case 131:    // [from doc]  The sweep-to-fill flag and display size are only valid for US stocks routed through SMART, and will be ignored.

        case 132:    // [from doc]  This order cannot be transmitted without a clearing account.

        case 133:    // [from doc]  Submit new order failed.

        case 134:    // [from doc]  Modify order failed.

        case 135:    // [from doc]  Can't find order with ID =

        case 136:    // [from doc]  This order cannot be cancelled.

        case 137:    // [from doc]  VWAP orders can only be cancelled up to three minutes before the start time.

        // 138, 129 vague

        case 140:    // [from doc]  The size value should be an integer:

        case 141:    // [from doc]  The price value should be a double:

        case 142:    // [from doc]  Institutional customer account does not have account info

        // 143 vague

        case 144:    // [from doc]  Order size does not match total share allocation.  To adjust the share allocation, right-click on the order and select “Modify > Share Allocation.”

        // 145 vague

        case 146:    // [from doc]  Invalid trigger method.

        …

        case 2102:    // [from doc]  Unable to modify this order as it is still being processed.

        case 2109:    // [from doc]  Order Event Warning: Attribute “Outside Regular Trading Hours” is ignored based on the order type and destination. PlaceOrder is now processed.

                    // actual:     Order Event Warning:Attempted modify of OutsideRth will not be done.  Order modify now being processed.

       

            // All the errors listed above are thought to be specific to Orders based on the message description.

            // It is sometimes unclear from the message whether the order id will be available with the error, or not.

            // Only errors with an id can be meaningfully routed to Order_error_Route.

            // All the rest might as well be routed right away to ReqTracker_error_Route.

            //

            // In any case the above list of errorCode's are treated as a list of what should be preferentially routed to orders before request trackers.

            // However the consequences of including an extraneous errorCode in the above list are non-existent for errors that turn out not to include a request id.

            // For errors with a request id, an extraneous errorCode in the above list is consequential only if it is NOT an order error,

            // but the request id coincidentally matches a currently-tracked order id.

            // It is hard to comment meaningfully on how obscure that is.

            // Instead it suggests motivation for a redesign that keeps order id's in their own numeric space,

            // or interleaves them in the same numeric space with other request id's.

            … rest of long comment omitted

            if (id != kIBNullReqId)

                handled = Order_error_Route (id, errorCode, errorString);

            else//10/14/12 was:  if (!handled)

                // So both kIBNullReqId errors and errors that are not successfully routed to an order based on the id will end up here.

                handledBy = ReqTracker_error_Route (id, errorCode, errorString);

                    // see comment in default case re ReqTracker_error_Route details

            break;

         

            //////////////////////////////////////////////// //////////////////////////////////////////////// /////////////////

           

         case 326:    // error -1 326 Unable connect as the client id is already in use. Retry with a unique client id.

            clientIdInUse = true;

            break;

       

        case 505:    // actual:    "request 2104 error 505 Fatal Error: Unknown message id."

            // Do not route this message–there should be no use in doing so since the connection is about to be closed.

            // Also see special case at top of this function.

            break;

       

        case 2100:    // actual:       New account data requested. API client has been unsubscribed from account data.

            handledBy = accountUpdateReqTracker .error_Route (id, errorCode, errorString);  // make sure AccountUpdateRequest::error_Generic gets this error

            AccountUpdatesCancelledByServer (errorString);

            break;

       

        default:

            handledBy = ReqTracker_error_Route (id, errorCode, errorString);

                // calls ActiveRequestCategoryManager::error_Route which calls ActiveRequest::error_Route for each outstanding request

                // which calls error_SpecificRequest for request with matching id if found

                // and may call error_Generic which is currently only implemented by AccountUpdateRequest

                // for error 2100 "New account data requested. API client has been unsubscribed from account data."

           

            if (handledBy == NULL)

                if (id != kIBNullReqId)

                    (void) Order_error_Route (id, errorCode, errorString);

            break;

    }

   

    return handledBy;

}

それ以外の場合は、ReqTracker_error_Routeを呼び出します 。これも理想的ではありませんが、完全に適切であり、これを実行します。

ActiveRequest *MyWrapper::ReqTracker_error_Route (const int id, const int errorCode, const CString& errorString)

{

    if (ActiveRequest *routedTo = historicalDataReqTracker  .error_Route (id, errorCode, errorString))

        return routedTo;

    if (ActiveRequest *routedTo = marketDataReqTracker      .error_Route (id, errorCode, errorString))

        return routedTo;

    if (ActiveRequest *routedTo = contractDetailsReqTracker .error_Route (id, errorCode, errorString))

        return routedTo;

    if (ActiveRequest *routedTo = realTimeBarReqTracker     .error_Route (id, errorCode, errorString))

        return routedTo;

    if (ActiveRequest *routedTo = accountUpdateReqTracker   .error_Route (id, errorCode, errorString))

        return routedTo;

    if (ActiveRequest *routedTo = marketDepthReqTracker     .error_Route (id, errorCode, errorString))

        return routedTo;

    if (ActiveRequest *routedTo = fundamentalDataReqTracker .error_Route (id, errorCode, errorString))

        return routedTo;

    if (ActiveRequest *routedTo = scannerReqTracker         .error_Route (id, errorCode, errorString))

        return routedTo;

    return NULL;

}

これは今度はこれを呼び出します

ActiveRequest *ActiveRequestCategoryManager::error_Route(const int id, const int errorCode, const CString& errorString)

{

    // Route all errors to all objects, until/unless an object's error_Route returns non-NULL, indicating it has "handled" the error.

    // In a typical implementation, generic errors (id == -1) will end up being routed to all objects,

    // and specific errors will be ignored except by the object with a matching request id (if any),

    // which will "handle" the error and return non-NULL (usually pointer to itself), preventing further looping here

    // (and in current implementation preventing equivalent of further looping in MyWrapper::ReqTracker_error_Route which calls this function for each request category until it is "handled").

    for (ActiveRequest *req = Next(); req != this; req = req->Next())

    {

        if (ActiveRequest *routedTo = req ->error_Route (id, errorCode, errorString))

            return routedTo;  // very likely routedTo will always equal req

    }

   

    return NULL;

}

そこで、 error_Routeの汎用実装が登場します。

ActiveRequest *ActiveRequest::error_Route(const int id, const int errorCode, const CString& errorString)

{

    if (this->ReqId() == id)

    {

        error_SpecificRequest (id, errorCode, errorString);

        return this;

    }

   

    if (id == kIBNullReqId)

    {

        if (errorCode == nonAPIErrorCode_connectionClosed)

            Aborted (errorCode, errorString);

        else

            error_Generic (errorCode, errorString);  // as of 5/3/12 this is the only call to error_Generic

    }

   

    return NULL;

}

また、 error_SpecificRequestの実装は、このような API リクエスト タイプごとにリクエスト追跡サブクラスによって提供されます。

void MarketDataRequest::error_SpecificRequest (const int id, const int errorCode, const CString& errorString)

{

    if (errorCode == 200)

    {

        Aborted (errorCode, errorString);

    }

   

    /* market data error reference

   

        error 39 200 No security definition has been found for the request

            the same error can happen for reqMktData and reqContractDetails and reqHistoricalData

            in this case it was a bogus combo (spread between AAPL and INTC options)

                sending MarketDataRequest 39 AAPL,INTC SPREAD

            but the "No security definition" error should be dispatched to the final request object

            and should maybe delete without cancel

           

        are there existing cases in which [??? text lost ???] caused an unintended cancel?

    */

}

したがって、アプローチの意味がわかるかもしれません。理想的ではありませんが、API を使用した作業のかなりの経験をサポートするアーキテクチャがたくさんあります。

-カート

【Q】「重複したrequestID」の値についての考え方(APIから与えられた不正な値)

詳細:

私のプログラムでは、TWS への接続時に NextValidId を取得し、これを使用します

その日の最初の注文をする番号、そして注文するまでインクリメントし続けます

それに続く命令。

昨日、ID によって返された NextValidId が重複していたことが起こりました。

1つプログラムは数日前に注文 ID 638 の注文を出しており、

ID 638 で別の注文をしました。

(両方の注文が実行されました)

TWSの「拒否された注文を再利用する」オプションのチェックを外しました — 注文

設定メニュー。

使用済みの OrderID が IB から返された理由を知っている人はいますか?

ありがとう、

ヴィシュルス

[A]フランク・ベル著

現在の注文の永続的なコピーを自分で保持する必要があることがわかりました

番号。 起動時に max(自分の番号、NextValidId) を使用します。

フランク

[A]リチャード・キング

TWS は、次の有効な ID を設定ファイルに保存します。これは大きな XML ファイルです。

そして、それはTWSをシャットダウンしたときにのみ書き出されるのではないかと思います(とは思いますが)

メニューに設定を保存するコマンドはありますか? – これを確認することはできません

一瞬)。

したがって、TWS がクラッシュした場合、または TWS をきちんと閉鎖せずに強制終了した場合、

あなたの観察を説明できるかもしれません。

リチャード

[A]ヤン・ボーネン著

念のため、EWrapper::openOrder( OrderId orderId, …) イベントの orderId も確認します。その注文 ID が次に使用されるものと等しいかそれより大きい場合、次に使用可能な値を orderId+1 に設定します。

「接続時に未決済注文をダウンロードする」オプションをチェックすると、開始時に未決済注文が自動的に受信されます。

asB

【Q】「requestID空間分割」についての考え方

こんにちは、カートさん

あなたが開発した建築構造にさらに光を当てていただき、ありがとうございます。

最も間違いなく、適切な応答ルーティング/処理のために対応するオブジェクトを迅速に取得するために、検索可能なリスト(または提案されたマップ)とともに個々のリクエストごとに1つの追跡インスタンスを持つアプローチを再利用します。

私は数週間前に非常によく似たものを開発していましたが、ロジックの一部はリクエスト ID の自動生成でした。その時点で、数か月前、もう簡単に見つけることができないトレッドの一部からリクエスト ID についてのあなたの意見を読んだことを思い出します。私の記憶が正しければ、注文リクエスト ID を他のすべての種類のリクエストとは別に追跡しているとおっしゃっていました。

もしそうなら、私の質問は、「注文のリクエストID」スペースと「他のリクエストID」スペースが重複している場合、どのように区別するのでしょうか?例: 1 つの注文追跡セットと「その他のリクエスト」セットからの 1 つと一致する ID を持つ error() 呼び出しを取得しました。するとルートがあいまいになってしまいました。

この問題についてさらに考えたとき、各リクエストに「有効期限」フィールドを追加するのが一般的に良いのではないかと思いました。有効期限が有限であるリクエストの場合はゼロ以外の値に、有効期限のないリクエストの場合はゼロの値に設定できます(データ サブスクリプションの場合と同様、キャンセルされるまで「永久に」存続する必要があります)。あるいは、あなたが言ったように、さらに良い方法として、これらのオブジェクトを処理し、どれを残し、どれを自由に移動するかを決定するのはクライアントの責任です。しかし、リクエスト追跡インスタンスのライフサイクルが短いと仮定しても、注文を他のものから分離しようとすると、頻度の低い「曖昧なルート」ケースが 100% 完了するわけではありません。(そもそもなぜこれを行う必要があるのか​​)。

ps: 他の可能性 (ID で他の注文と区別する必要がある場合) は、注文と他のリクエストに奇数の数字を使用し、それらのスペース (Linux OS で割り当てられるプロセス ID のように) を囲むことですが、醜くて不必要に縮小されます。 ID 用のスペースが 2 回あります (注文と他のリクエストに対して同じセットのパワーが必要かどうかは疑問です)

ありがとう、

ドミトリー

[A] by Kurt (このスレッドから: C++ アーキテクチャの質問) 

[をちょきちょきと切る]

 

私は数週間前に非常によく似たものを開発していましたが、ロジックの一部はリクエスト ID の自動生成でした。その時点で、数か月前、もう簡単に見つけることができないトレッドの一部からリクエスト ID についてのあなたの意見を読んだことを思い出します。私の記憶が正しければ、注文リクエスト ID を他のすべての種類のリクエストとは別に追跡しているとおっしゃっていました。

もしそうなら、私の質問は、「注文のリクエストID」スペースと「他のリクエストID」スペースが重複している場合、どのように区別するのでしょうか?例: 1 つの注文追跡セットと「その他のリクエスト」セットからの 1 つと一致する ID を持つ error() 呼び出しを取得しました。するとルートがあいまいになってしまいました。

私がこれまでこのアプローチでうまくいったからといって、それが最善であるとか、これからもこのアプローチでうまくいくというわけではないことに注意してください。私は差し迫った問題ではない問題に取り組むのが好きなので、さまざまな角度から検討し続けることができます。あるいは、無期限のままにしておくこともできます。 requestID スペースを分割している人もいます。リチャードはこれをやったと思います。十分に広い空間であると指摘されています。

私はたまたま小さな数字が好きなので、注文 ID には小さな数字を使用し、他のリクエスト ID には小さな数字を使用します。あなたの奇数/偶数のアイデア(以下)もこれに対処しますが、IBが次の整数値であなたの代わりに別のorderIDを自動的に挿入する可能性がある特定の種類の注文では問題が発生する可能性があるという記憶があります。

私がこれを回避する理由は、エラー コード スペースが IB によってある程度定義されているためです。IB ドキュメントに基づくと、私が言及したが示さなかった MyWrapper::error_Route 関数には、特に errorCode に関する大きなスイッチと、注文に特有であることが知られているエラーの長いリストがあります。これは、注文関連のエラーの長いリストが切り捨てられた関数です。

ActiveRequest *MyWrapper::error_Route(const int id, const int errorCode, const CString& errorString)

{

    if (errorCode == 505)

        // actual:    "request 2104 error 505 Fatal Error: Unknown message id."

        printf ("generic error %d %s [id=%d]\n", errorCode, errorString.CStr(), id);

    else if (id == kIBNullReqId)

        printf ("generic error %d %s\n", errorCode, errorString.CStr());

    else

        printf ("request %d error %d %s\n", id, errorCode, errorString.CStr());

   

    bool handled = false;

    ActiveRequest *handledBy = NULL;

   

    switch (errorCode)

    {

        // errors specific to Orders

        case 103:    // [from doc]  Duplicate order ID.

        case 104:    // [from doc]  Can't modify a filled order.

        case 105:    // [from doc]  request 45 error 105 Order being modified does not match original order

        case 106:    // [from doc]  Can't transmit order ID:

       

        …

        case 121:    // [from doc]  Invalid BD flag for the order. Check "Destination" and "BD" flag.

        case 122:    // [from doc]  No request tag has been found for order:

        // 123, 124 vague

        case 125:    // [from doc]  Buy price must be the same as the best asking price.

        case 126:    // [from doc]  Sell price must be the same as the best bidding price.

        case 129:    // [from doc]  VWAP orders must be submitted at least three minutes before the start time.

        case 131:    // [from doc]  The sweep-to-fill flag and display size are only valid for US stocks routed through SMART, and will be ignored.

        case 132:    // [from doc]  This order cannot be transmitted without a clearing account.

        case 133:    // [from doc]  Submit new order failed.

        case 134:    // [from doc]  Modify order failed.

        case 135:    // [from doc]  Can't find order with ID =

        case 136:    // [from doc]  This order cannot be cancelled.

        case 137:    // [from doc]  VWAP orders can only be cancelled up to three minutes before the start time.

        // 138, 129 vague

        case 140:    // [from doc]  The size value should be an integer:

        case 141:    // [from doc]  The price value should be a double:

        case 142:    // [from doc]  Institutional customer account does not have account info

        // 143 vague

        case 144:    // [from doc]  Order size does not match total share allocation.  To adjust the share allocation, right-click on the order and select “Modify > Share Allocation.”

        // 145 vague

        case 146:    // [from doc]  Invalid trigger method.

        …

        case 2102:    // [from doc]  Unable to modify this order as it is still being processed.

        case 2109:    // [from doc]  Order Event Warning: Attribute “Outside Regular Trading Hours” is ignored based on the order type and destination. PlaceOrder is now processed.

                    // actual:     Order Event Warning:Attempted modify of OutsideRth will not be done.  Order modify now being processed.

       

            // All the errors listed above are thought to be specific to Orders based on the message description.

            // It is sometimes unclear from the message whether the order id will be available with the error, or not.

            // Only errors with an id can be meaningfully routed to Order_error_Route.

            // All the rest might as well be routed right away to ReqTracker_error_Route.

            //

            // In any case the above list of errorCode's are treated as a list of what should be preferentially routed to orders before request trackers.

            // However the consequences of including an extraneous errorCode in the above list are non-existent for errors that turn out not to include a request id.

            // For errors with a request id, an extraneous errorCode in the above list is consequential only if it is NOT an order error,

            // but the request id coincidentally matches a currently-tracked order id.

            // It is hard to comment meaningfully on how obscure that is.

            // Instead it suggests motivation for a redesign that keeps order id's in their own numeric space,

            // or interleaves them in the same numeric space with other request id's.

            … rest of long comment omitted

            if (id != kIBNullReqId)

                handled = Order_error_Route (id, errorCode, errorString);

            else//10/14/12 was:  if (!handled)

                // So both kIBNullReqId errors and errors that are not successfully routed to an order based on the id will end up here.

                handledBy = ReqTracker_error_Route (id, errorCode, errorString);

                    // see comment in default case re ReqTracker_error_Route details

            break;

            /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

           

        case 326:    // error -1 326 Unable connect as the client id is already in use. Retry with a unique client id.

            clientIdInUse = true;

            break;

       

        case 505:    // actual:    "request 2104 error 505 Fatal Error: Unknown message id."

            // Do not route this message–there should be no use in doing so since the connection is about to be closed.

            // Also see special case at top of this function.

            break;

       

        case 2100:    // actual:       New account data requested. API client has been unsubscribed from account data.

            handledBy = accountUpdateReqTracker .error_Route (id, errorCode, errorString);  // make sure AccountUpdateRequest::error_Generic gets this error

            AccountUpdatesCancelledByServer (errorString);

            break;

       

        default:

            handledBy = ReqTracker_error_Route (id, errorCode, errorString);

                // calls ActiveRequestCategoryManager::error_Route which calls ActiveRequest::error_Route for each outstanding request

                // which calls error_SpecificRequest for request with matching id if found

                // and may call error_Generic which is currently only implemented by AccountUpdateRequest

                // for error 2100 "New account data requested. API client has been unsubscribed from account data."

           

            if (handledBy == NULL)

                if (id != kIBNullReqId)

                    (void) Order_error_Route (id, errorCode, errorString);

            break;

    }

   

    return handledBy;

}


したがって、このコードは、エラー コードが注文を処理することが特にわかっている場合を除いて、最初にエラーを注文にルーティングしないという点で誤りです。これによる最悪の結果は、実際にはそれほど悪いことではありません。なぜなら、ほとんどの場合、オーダー コールバック メッセージが物事の基本的な状態を処理し、予期しない状態変化が発生した場合、最悪の場合、おそらく理由を説明するメッセージがログに記録されるからです。この時点で、宛先コードを必要に応じて変更できます。

私は必ずしもこのアプローチを推奨しているわけではありませんが、私がとった方法です。

[A]リチャード・L・キング著

 ID 空間の分割に関しては、次の範囲を使用ます

さまざまなリクエストタイプ。

市場データリクエスト: 0 – 0x3FFFFF

マーケットデプスリクエスト: 0x400000 – 0x7FFFFF

履歴データリクエスト: 0x800000 – 0x80FFFF

実行詳細リクエスト: 0x810000 – 0xFFFFFF

契約詳細リクエスト: 0x1000000 – 0xFFFFFFF

注文 ID: 0x10000000 – 0x7FFFFFFF

 この方法でIDを分割すると、どのタイプの ID かを簡単に識別できるようになります。

エラーメッセージが参照するリクエスト。確かにエラーは直接ルーティングできます。

その種のリクエストのハンドラーに送信します。

これらの大きさや配置には特に意味はありません

範囲は、すべての人にとって十分な大きさであるという事実を除けば、

実用的な目的 (間違いなく、誰かが実行して私が間違っていることを証明してくれるでしょう)

1日あたり10000注文で514.8年間クライアントを取引していますが、私は気にしないかもしれません

それまでに)。

私の API 実装では、クライアントは範囲内の ID を使用してリクエストを作成します。

0 から n まで。n はリクエストのタイプによって異なり、

ID 範囲。したがって、市場データのリクエスト ID は 0 ~ 4194303 の範囲になります。

実行詳細リクエスト 0 ~ 8323071。このアプローチにより、クライアントは

関連するハンドラーを見つけるための配列へのインデックスとしてのリクエスト ID

リストを検索したりハッシュ検索を使用したりするのではなく、応答のオブジェクトを使用します。

(時間の節約はまったく関係ありませんが、この種のことは私の興味をそそります

虚栄心)。

リクエストが行われると、API コードは呼び出し元のリクエスト ID を次のように変換します。

適切な基本値を追加することで TWS の ID 空間を作成します。また、その逆の場合も同様です。

応答を渡します。

注文 ID は、クライアントが関与しないという点で若干異なる方法で処理されます。

それらを割り当てる際に。placeOrder メソッド自体が ID を

指定された注文オブジェクト。指定された注文にすでに

ID がゼロ以外の場合、これは単なる注文変更であり、ID を変更する必要はありません。

割り当てられました。明示的なmodifyOrderメソッドを使用することも検討しましたが、決定しました。

それに対して。

リチャード

[Q] 注文を変更しようとすると失敗することがあります!

[A]  by Kurt (この スレッドから抜粋)

それは解決策かもしれませんが、問題には対処していません。これが何です

*かもしれません*それはあなたの問題です。私がそうしているのは「標準的な」症状なので、

馴染みがあると思います。保存するとこの問題が発生します

openOrder メッセージによって返された注文を後続の呼び出しに使用します

注文する。

processMsg のバグです。C++ ではバグは次のとおりです。

EClientSocketBase::processMsg、OPEN_ORDER の場合。

TWS API の新しいリリースごとに、私はそれを調べて同じものを作ります

修正します。次の 5 行のブロックを参照してください。変更箇所は 2 つにマークされています。

場所:

DECODE_FIELD_MAX/*kkb – は DECODE_FIELD*/( order.volatility); でした。// バージョン11

分野

DECODE_FIELD(order.volatilityType); // バージョン11フィールド

DECODE_FIELD(order.deltaNeutralOrderType); // バージョン 11 フィールド (ハッキングがありました)

バージョン11の場合)

DECODE_FIELD_MAX/*kkb – は DECODE_FIELD*/(order.deltaNeutralAuxPrice); でした。

// バージョン 12 フィールド

DECODE_FIELD(order.continuousUpdate); // バージョン11フィールド

問題は、IB のコードがデフォルトで order.volatility と

deltaNeutralAuxPrice フィールドが欠落している (空の) 場合、フィールドが誤って表示される

string) を受信した OPEN_ORDER メッセージから取得します。DECODE_FIELD_MAX ではなく

DECODE_FIELD は、空の文字列の場合を検出し、文字列を置き換えるために必要です。

適切な「UNSET」値、この場合は UNSET_DOUBLE (次のように定義されています)

DBL_MAX、したがって DECODE_FIELD_MAX という名前になります)。

DECODE_FIELD と DECODE_FIELD_MAX はおそらく一致するはずです。

Order コンストラクターによって設定されるデフォルト値。これらの 2 つのケースでは、デフォルト値が設定されます。

そうではなく、問題が発生します。Order コンストラクターを調べて数値を確認します。

フィールドが初期化されます。ゼロに初期化されるものもあれば、

型に応じて UNSET_DOUBLE または UNSET_INTEGER に初期化されます。

processMsg はおそらく、欠落しているフィールドに対して UNSET 値を使用する必要があります。

欠落している短いメッセージ フィールドは、オーダーが指定するデフォルト値を取得する必要があります。

コンストラクターがそれらを与えたでしょう。あるいはそれが合理的なモデルだと思います

ともかく。

この問題の結果、openOrder メッセージは破損した注文を返します。

あなたへ。placeOrder と一緒に使用すると失敗します

に適用されないフィールドの値 UNSET_DOUBLE を確認したいと考えています。

ノンボラティリティ注文。代わりに、openOrder はこれらのフィールドにゼロを入れます。

上記の 2 つの修正を行うと、問題は解決します。この2つだけです

EClientSocket のものに加えた修正。他にもあるかもしれないと信じています

processMsg が Order コンストラクターと一致しない場所、そして私は

どこかで指摘されていましたが、実際に問題が発生したわけではないので、

API リリースごとにわざわざ修正する必要はありません。

-カート

[Q] トレーリングストップを変更しようとすると、エラー 10067 が発生しました

[A] by Joshオンラインで表示/返信 (#39111)

2017 年 12 月 13 日に追加

したがって、注文はすぐにはトリガーされず、19:25:02にトレイルストップ価格が割り当てられなかったようです。したがって、トレイルストップ価格を指定せずに変更することができます。その後、市場で取引が発生し、システムがトレーリングストップ価格で注文を変更するようになりました。注文を再度変更しようとすると (19:25:06)、トレーリングストップ価格が変更されたため、システム内の注文と一致しなくなりました。その時点で注文を変更するには、トレーリングストップ価格を示さない最初の orderStatus の代わりに、返された最新の orderStatus() メッセージ内の Order オブジェクトを使用する必要があります。

[Q] 注文実行メッセージに関する考慮事項

[A]  by Kurt (ここから)

「複数の」メッセージに関して何かが欠けている可能性がありますが、危険です。

推測。

同じ execId を持つ 2 つの実行メッセージを決して取得しないでください。あなたが持っている

信頼性が必要な場合は、そのようなものを追跡します。重複

メッセージは命令であろうと実行であろうと問題にはなりません。

必要な情報を保持している限り。(まあ、話すことはできませんが、

Excel 内で可能なこと。)

オブジェクトごとに状態を把握するのは面倒だと考える人もいます

彼らは懸念している。しかし、そうしない場合の悩みは計り知れません。あなた

実際には存在しない問題を引き起こす。IB は、

状態を追跡せずに使用しても信頼できる種類のシステム

もう一方の端に。したがって、必要な情報を維持しないと、

その結果として得られる問題は、本質的にはあなたが作り出した問題です。

いつでも実行をリクエストでき、その後さらに多くのものが得られます

「重複」ですが、すでに受信したものは無視してください。私としては

一部の人々は、目に見えているという理由で明示的に処刑を要求していることを思い出してください。

実行メッセージがドロップされます。(これが両方の注文を追跡する理由です

おそらくどちらかがドロップされる可能性があるため、実行も可能です。)

-カート

【Q】API接続確認・ティックの適時確認

[A1]  by rwk2095

> 私は、そうすべきだとわかっている号 (ES や QQQQ など) を購読しています。

> 更新中。入札やオファーを含むすべての更新にタイムスタンプを付けます。

> 期限内にアップデートを受信しなかった場合は警報音を鳴らします

> 10 秒などの一定の時間間隔。

そのアイデアは気に入っています、ありがとう。株式固有の問題は除外されますが、すべての接続性と市場固有の問題を 1 つの小さなサブウーファーでキャッチできるのは素晴らしいことです。

[A2]マイク・スミス 著

ポジションをエントリーする際、私の ATS は出来高の高速移動平均を監視し、出来高が特定のポイントを超えて加速または減速している場合 (バックテストで確認)、それは「悪いこと」であると判断し、取引を行いません。何らかの理由でダニが来なくなった場合に対処する副作用として。

さて、あなたが説明している非常に遅い市場の場合は、バックテストする必要がありますが、同じことがわかるかもしれません。つまり、出来高がほとんどまたはまったくない(非常に)長い一時停止は理想的なエントリーポイントではないため、同じ手法が機能する可能性があります。しかし、私がやることは 2 つあります。(1) 取引所として SMART を使用しないでください。取引する市場で最も取引量の多い取引所を使用します。株式の場合は、通常、そのシンボルの NYSE または最も取引量が多い ECN です。(2) 同じ取引所とそのシンボルの reqMarketData を使用して大量のシンボルを見つけますが、データを捨てて一時停止を探します。でも、ジムの言う通り、どうするつもりですか?私は通知システム (テキスト メッセージと電子メール) を持っており、何か異常なことが起こったときに作動します。場合によっては、その場にいて「人間的な」判断を下す必要がある場合があり、ティックの長い停止もその 1 つです。

マイク

[Q] AvgPrice は 2 桁に四捨五入されていますが、3 桁にしたいのです!-)

[A]この スレッドを読んでください

[Q] 複数の約定済み注文ステータス更新の avgFillPrice を取得するにはどうすればよいですか?

[A] by alex_7880

orderStatus() も「int 残り」を返します。私のロジックは基本的に、注文が約定されたと判断する前に残りが 0 になるのを待つというもので、残り = 0 のときに返される「double avgFillPrice」を使用します。

[Q] 金融商品のティックサイズへの四捨五入について

この スレッドの Mike Smith による[A]

小数点以下の桁数の計算を自動化できます。これは私がとったアプローチであり、分数ティックを持つ ZB でも機能します。私は、あなたが望むことを行うnearestTick()メソッドを含むSymbolInfoクラスを持っています。

class SymbolInfo {

// This is assigned a value in constructor (below)

private int tickSize;

////////////////////////////////////////////////////////////

// Note: These two class vars are used only by nearestTick()

//

// The value of nearestTickMultiplier is based on the number

// of digits in the fractional part of the tick size. It's

// 10 to the power of that many digits. So if the tick size

// is a penny (0.01) then the number of digits in the

// fractional part is 2 and nearestTickMultiplier is 100.

private long nearestTickMultiplier;

//

// The value of tickSizeMultiplied is the tick size multiplied

// by nearestTickMultiplier. It is used to calculate the price

// as a long int which is the smallest possible long int which

// can be used to calculate the price by converting it to a

// double and dividing by nearestTickMultiplier. This guarantees

// price is a power of 10 without roundoff errors.

private long tickSizeMultiplied;

//

// Another example would be for futures contracts which use 1/32

// as a tick size which is 0.03125. In this case the number of

// digits in the fractional part is 5 so nearestTickMultiplier

// would be 100000 and tickSizeMultiplied would be 3125.

//

// This would also come in handy for representing tick values of

// FOREX symbols where one currency relative to the Dollar might

// be something in the neighborhood of 0.000000000001 to 1 (or

// visa-versa the way things are going lately).

///////////////////////////////////////////////////////////////

// Constructor

public SymbolInfo(ContractDetails contractDetails) {

tickSize = contractDetails.m_minTick;

int n = getFractionDigitCount();

// nearestTickMultiplier is always 1 or greater.

nearestTickMultiplier = Math.round(Math.pow(10.0, n));

tickSizeMultiplied = Math.round(tickSize * nearestTickMultiplier);

}

/**

* Get number of digits in fractional part of tickSize

*

* @return Number of digits in fractional part of tickSize

*/

public final int getFractionDigitCount() {

double fraction = tickSize – ((long)tickSize);

String s = Double.toString(fraction);

int n = s.length();

if (s.contains(".")) {

if (s.equals("0.1")) {

n++; // force trailing zeros, just looks better (GC)

} else {

while (s.charAt(n-1) == '0') {

n–;

}

}

}

if (s.startsWith("0")) {

n -= 1; // remove leading zero

}

n–; // remove decimal point

return n;

}

/**

* Round given price to nearest tick boundary so

* the returned value is a multiple of the tick size

* for this instrument.

*

* @param price The price we want to adjust

* @return The price adjusted to the nearest tick boundary

*/

public final double nearestTick(double price) {

long ticks = Math.round(price/tickSize);

price = (double)(ticks * tickSizeMultiplied);

return price/nearestTickMultiplier;

}

}


[Q] MKT注文とLIMIT注文のどちらを使用すればよいですか?部分的なフィルを追跡するにはどうすればよいですか?

この スレッド の tdrtw による[A]

ロジャー、あなたは部分約定を持っていて、価格があなたの方向に動いたので、部分約定が紙上の利益になったと仮定します。

私が手動で取引していたときは、ストップリミット注文を使用してその価格を指定してエグジット価格でエントリーし、動きの速い市場で部分的に約定することがよくありました。時々、待っていると価格が戻ってきて、約定が完了することがありました。

完全自動システムに移行したとき、ルールを変更し、指値なしでストップ注文でエントリーすることにしました。

さて、これにより平均エントリースリッページは増加しましたが、私はそれから多くの利益を得ました。

1) これまでのところ、すべてのエントリーオーダーは常に約定しています。

2) エントリー注文が約定されたので、一瞬のうちにエグジット注文が出されます。これは、部分的な塗りつぶしが公開されていて、これを管理するための複雑なソフトウェア ルールが存在するよりもはるかに安全です。

3) 今では、動きの速い市場を捉え、かつてはストップ リミット エントリーを使用できなかった注文で利益を得ることができます。

4) はい、時々スリッページが私に不利になることがあります。

全体として、システムのパフォーマンスに悪影響があることは見つかりませんでした。どちらかと言えば、完全に自動化されているためシステムのパフォーマンスが向上しており、チャートを見てその瞬間に追われることなく、自分の時間を有効活用してより良い作業を行うことができます。

私のシステムは、正確な価格での STOP-Limit エントリーよりも、STOP エントリーを使用したオートモードの方がはるかに安全です。

難しいかもしれないことは承知していますが、複雑なソフトウェア プログラムを作成して現在のルールを強制的に実行させるよりも、ソフトウェアに合わせてシステムを変更する方が良い場合もあります。

自動化されてからは、プログラムが簡単で、問題が発生する可能性が低い、はるかにシンプルなシステムを作成するようになりました。

それは単なる私の意見です。

幸運を!

ダミアン

(別名 Exotric_Adriana_1982 😉)

[Q] なぜ PosixMQ が IPC にとって良いアイデアなのでしょうか? スレッドセーフなキュー (ミューテックス付き) を使用できないのはなぜですか?

[A]スタックオーバーフロー のNils Pipenbrinckによる

リアルタイム OS 環境では、固定スケジュールでのコードの実行を保証する必要があるという問題に直面することがよくあります。たとえば、正確に10 ミリ秒ごとに呼び出される関数があるとします 。それより早くも遅くもありません。

このような厳しいタイミング制約を保証するには、いかなる状況でもタイム クリティカルなコードをブロックしてはならないコードを作成する必要があります。

の posix スレッド同期プリミティブはここでは使用できません。別のプロセス/スレッドによってすでにロックされている可能性があるため、タイム クリティカルなコードからミューテックスをロックしたり、セマフォを取得したりしないでください。ただし、多くの場合、タイム クリティカルなコードから他のスレッドのブロックを解除することが許可されます (たとえば、セマフォの解放は問題ありません)。

このような環境では、メッセージ キューは、ブロックすることなく、あるスレッドから別のスレッドにデータを渡すクリーンな方法を提供するため、データ交換に最適です。

単に変数を設定するためにキューを使用するのはやりすぎのように聞こえるかもしれませんが、これは非常に優れたソフトウェア設計です。この方法で実行すると、タイム クリティカルなコードへの明確に定義されたインターフェイスが得られます。

また、競合状態の問題に遭遇することがないため、決定論的なコードを書くのにも役立ちます。メッセージキューを介して変数を設定すると、タイムクリティカルなコードが送信されたのと同じ順序でメッセージを確実に認識できるようになります。ダイレクト メモリ アクセスとメッセージを混在させる場合、これを保証することはできません。

[A2] by Alok スタックオーバーフロー から保存

メッセージ キューは、2 つの異なるプロセス間でデータを交換する必要がある場合に、主にIPC メカニズムとして使用されます。ただし、メッセージ キューはスレッド コンテキストの切り替えにも使用される場合があります。たとえば:

ドライバーの上にあるソフトウェア層にコールバックを登録します。コールバックはドライバーのコンテキストで返されます。これはドライバーによって生成されたスレッドです。これで、ドライバのスレッド内で多くの処理を実行してこのスレッドを占有することがなくなりました。したがって、コールバックで返されたデータをメッセージ キューに追加すると、データの処理を実行するためにアプリケーション スレッドがブロックされます。

[100% 完成したフレームワークからのフィードバック;-]

[A] by poch32

セキュリティに応じて、私の ATS は現在 3 ~ 8 つの戦略をチェックします。戦略には「特権リング」 (OS 用語で言えば) が与えられるため、衝突が発生した場合には、常に一方が他方の中で優先されます。

2 つの対立するアルゴリズムを使用できるシナリオがいくつかあります (エリックが以前に提案した、異なる時間枠のアルゴリズムが良い例です)

ただし、私の場合、すべての戦略が多かれ少なかれ同じ時間枠を指向しているため、2 つ以上の戦略が衝突することは許可できません。それは事実上、通信でお金をばら撒くことになるからです。

ATS の 2 つの独立した同時インスタンスが実行されており、同時戦略の衝突を許可する必要がある場合、私は明らかにパイプ/tcpip ルートを選択するでしょう。遅かれ早かれ ATS の 1 つを別のマシンに移動する必要が生じる可能性があるため、できれば最後のものです。

[A] by tdrtw

私は複数の Future Contracts で複数のシステムを実行しています (ただし、同じ契約タイプで 2 つのシステムを実行することはありません)。

Windows XP Pro マシン上で実行され、Oracle XE データベースと通信するシェル Java コンソール アプリを作成しました。

シェル Java コンソール アプリは 1 つの金融商品 (以下、FI) のみを取引できます。これは、.jar ファイルを開始するときの入力パラメータであり、データベース コントロール テーブルにマップされ、有効期限、取引のリスクの大きさ、ティック サイズ、戦略タイプなどのすべての情報を取得します。

データベース管理テーブルは、どのような戦略で取引するかを指示します。Java コンソール アプリは、Oracle ストアド プロシージャへの汎用呼び出しを行い、Oracle ストアド プロシージャにコーディングされたばかりの正しい戦略を呼び出します。

基本的に、毎日起動するときに、Java コンソール アプリの複数のインスタンスを起動し、それぞれが独自の戦略を取引する異なる FI を指します。

何度も道を間違えたので、うまくいくまでに時間がかかりました。しかし、一つ言えるのは、これは素晴らしく機能するということです。そして、ご存知のとおり、私はそれを少し誇りに思っています 🙂

私には Oracle データベースに関する以前のスキルがありましたが、何年も前に自動化事業を始めたときは Java のスキルはまったくありませんでした。そこで、Oracle Database のスキルに頼って、コードを Java と oracle pl/sql に分割しました。

今考えると大したことではありませんが、最初は少し大変でした。貼り付けると所定の位置に落ちます。ただ立ち止まっているよりも、10歩進んで5歩下がるほうが良いでしょう。

また、これらのボードに寄りかかりすぎないように注意してください。かつて経験者の隣に座ったとき、自分が答えを導き出すことができる質問をし続けていたことを覚えています。その人が引っ越してからは、自分で物事を解決するようになり、沈んだり泳いだりしても実際にそれができることに実際に自分自身で驚きました。

幸運を祈ります、あなたは最終的に自分の道を見つけるでしょう!

ダミアン

[A] リチャード・L・キング著

注: まず、IBController は現在、事実上 IBC に取って代わられることに注意してください。この変更の理由については、こちらをご覧ください。おそらく IBC への切り替えを検討する必要があります。

2. 構成データに基づいて IBController の 1 つ以上のインスタンスを実行する完全に別個のデーモン プロセスを開発します。たとえば、月曜日の朝 06:00 にライブ アカウントで IBController を実行し、金曜日の 22:00 に (IBController のコマンド チャネル経由で) 停止します。これら 2 つの時点の間のいずれかの時点で IBController プロセスがドロップアウトした場合は、プロセスを再起動します。IBControllerService サンプルには、Windows 上でこれを実行するためのサンプル コードがすでに存在していることに注意してください (ただし、今説明したものよりも洗練されていません)。

実際、私は Windows タスク スケジューラのみを使用して、2. と非常によく似たことをすでに実行しています。したがって、たとえば平日に停電が発生した場合、または IBController/TWS がクラッシュした場合 (実際にはクラッシュしませんが)、電力が再開されると IBController は自動的に再起動されますが、週末の故障の場合はそうではありません。

私が行っていないのは、TWS や API のアクティブな監視 (何らかの方法で監視すること) です。これは、11 年間、毎日取引日に一日中 API プログラムを実行してきた中で、その必要性を一度も見つけたことがないからです。(実際の走行距離は異なる場合がありますが、その理由はわかりません。ただし、API を通じて 1 時間あたり数百件の注文をプッシュしたり、履歴データを継続的にダウンロードしたりしていれば、状況は別になるでしょう。)

また、ある意味で IBController が「準備完了」するまでトレーディング システムを待つ必要もないと思います。私のプラットフォームは、IBController または TWS が実行されているかどうかをまったく気にしません。そのように構成されている場合は、成功するまで定期的に接続を再試行し続けるだけです。実際、私はほとんどの API プログラムを、IBController/TWS/Gateway を実行しているマシンとは別のマシンで実行しています。

[Q]単体テスト – どれを選択しますか?

[A] by Dmitry (2015 年 5 月 7 日に追加)

C++ 単体テストに関する非常に優れた記事

「C++ 単体テスト フレームワーク ジャングルを探索する」

http://gamesfromwithin.com/exploring-the-c-unit-testing-framework-jungle

以下も参照してください:

http://stackoverflow.com/questions/1407354/is-there-ac-unit-testing-library-that-is-similar-to-nunit

単体テストの比較に関する優れた Wiki (他の言語もあります!)

http://en.wikipedia.org/wiki/List_of_unit_testing_frameworks

[その他の混沌とし​​た実装メモ]

———————————————————————————————————–

ティックモメンタムインジケーター

MarketMole によるアイデア (このスレッドから)

また、現在のビッド/アスクスプレッドに関する限り、取引がどちら側についたかを実際に判断しようとするティックモメンタムインジケーターも構築しました。私がさまざまなブローカーに対してこれらを実行したことは知っていますが、私はいつかIBに対しても実行したと確信しており、広い意味で一般的な取引サイドを判断できた(と思っていました)。

———————————————————————————————————–

トピック: 「何を[リモートで]監視するか」

この スレッドからの Jason Sapp による

私は GUI を通じて実際のポジションを監視するのではなく、純損益、最悪の状況、未実現損益、実現損益、ポジション数 (ロング/ショート)、逃したポジションなどを監視するだけです。各位置を監視する機能を入れようと考えましたが、まだ実行していません。また、最終的には(必要に応じて)ポジションを手動でクローズする機能を実装したいと考えていますが、(もう一度言いますが)実際にそうする必要はありません。

どのようなものかを確認できるようにスクリーン ショットを添付しました (昨日はたまたま私にとって良い日だったので、リアルタイム グラフは非常にきれいに見えます)。(添付のグラフの) 黄色の線の終点付近で、最悪の場合の純損益が上回っている部分に異常があることをご容赦ください。これは、ポジションが決済される瞬間のデータを時々取得する方法です。バグを修正する時間が取れていないだけです。

3h2dg.jpg

注: これはhttp://www.amcharts.com/demos/を使用して描画されました。

———————————————————————————————————–

直感的ではありませんが、IB は価格とサイズの差分のみを送信します。

ティックイベントを完了します。

前の価格メッセージと同じ価格で取引が発生した場合、

サイズメッセージのみを取得します(価格は暗黙的に以前の価格です)

メッセージ)。

———————————————————————————————————–

rwk: 注文ステータス イベントはログ記録にのみ使用します

zsolt: 最後の質問です。OrderStatus と Exections データを関連付けて、次のようにする価値があります。

同意しない場合は、TWS および/または ATS が機能することを確認するためにアラートが表示されます。

それとも、実行データは実際に信頼できるものですか?

———————————————————————————————————–

私は(接続中に)処刑を見逃したことはありませんが、他の人はここにいます

持っている。*私*は死刑を逃していませんが、他の人はここにいます

したがって、IB は 100% 信頼できるわけではなく、execDetails を使用するだけです。

調整コードと再生コードを作成する必要があります。

接続が切断された場合に必要になるためです。

———————————————————————————————————–

よかった、ありがとう。先週、私は調整コードを作成しました(名前も付けました)

私のクラスは OrderReconciler :) で、データベース内の永続化された状態を次のものと比較します。

注文と約定データをオープンし、約定とキャンセルを

alg を使用してメモリとデータベースの状態を更新します。

このようにして、コンテキストを失わずにアプリを再起動できますが、当然のことながら、

取引の機会を逃す可能性があります。

これまでのところ、これは正しく動作しているようです。

execdetails について皆さんにご提案いただきありがとうございます。

———————————————————————————————————–

そう、re updatePortfolio です。そしてあなたのシナリオは私と同じ理由です

rwk のアプローチは使用しないでください。ただし、対立するものを調整する場合は、

お互い、特に取引中*、updatePortfolio は潜在的にひどいものになる可能性があります

updateportfolio で予測されない変更が発生した場合に便利です

受け取った命令/実行メッセージによって、あなたがあなたであることがわかります。

おそらく何かを見逃したでしょう。その条件下では、コードはリクエストすることができます

注文をオープンしたり、執行を再度リクエストしたり、アラームを生成したりすることができます。

その状態を検出するためのロジックは簡単ではなく、おそらく次のことが必要です。

ある程度の時間差があれば、考えられるすべての注文の組み合わせを検討できる可能性があります

実行された、または部分的に実行された*可能性がある*など。

-カート

———————————————————————————————————–

[「ストップリミット注文の設計」に関する優れた実装メモ]

ここにあります:ソース

考えられる解決策:

OCO で逆指値注文と逆指値注文の両方を使用する

たとえば、10.00のストップを購入したいとします。

したがって、10.00 にストップリミット注文を出し、10.10 に買いストップ注文を出します。

確実に 1 つの注文だけがトリガーされるように OCO させます

———————————————————————————————————–

ContractTracker 実装に関する注意事項

「speculant」で ContracTracker クラスを作成しました。これは内部で 3 ~ 5 の IB API リクエストを処理し、フレームワークに履歴とリアルタイム データ (価格ティック、リアルタイム バー) を提供します。

高レベルの詳細は次のとおりです。

基本的に、IB は特定の契約の価格を取得する 5 つの方法を提供します。

  1) reqMktData は、サンプリングされた価格更新をストリームアップします (たとえば、1 秒あたり 3 ~ 5 個の価格値を取得しますが、高値/安値を見逃す可能性があります)

  2) reqHistoricalData (引数 "keep_up_to_date" を true に設定) – これにより、現在までの履歴から足が得られ、その後も足の更新情報が送信され続けます (これも 1 秒あたり 3 ~ 5 回、ただし 1 つの価格値だけではなく、全体の値) OHLC 値が更新された現在のバー) – 正確な制限は忘れましたが、50 を超える「リアルタイム」リクエストを同時に実行することはできないと思います。したがって、「3)」と「1)」も使用すると –これらすべてがカウントされるため、プラットフォーム内の各契約ごとに 3 種類すべての「リアルタイム」更新を行いたい場合、実際の制限は同時に約 50/3 = 16 契約となり、それ以上は制限されません:(

  3) reqRealTimeBars – これは、5 秒のバー更新をあなたにのみ送信します (5 秒ごとに 1 回の更新)。

  4) その後、数千の更新を伴う実際のティックへのサブスクリプションがありますが、契約サブスクリプションは 3 つまでに制限されています

  5) さらに、すべてのビッドとアスクも取得できる「深さ」があります (レベル 2)

私の目標は、最大 50 件の契約をリアルタイムで追跡できるようにすることです。

最初の 3 つだけを使用し、いくつかの履歴を要求するクラス (Java) を配置しますが、「最新の状態を保つ」を true に設定せずに (履歴のみを要求します)、次に 5 秒間のリアルタイム バーを要求します。サンプリングされた価格の更新用 (reqMktData)。

次に、それらを「マージ」し、受信したすべての更新を使用して独自の 1 分足、「改良された」5 秒足を作成します (5 秒ごとに 1 回更新する代わりに、ティック価格の更新ごとにバーが 1 秒あたり数回更新されました)。また、合成の 1 日バーも作成します。


0 件のコメント :

コメントを投稿