これはFreya Financeの構築についての短いシリーズの締めくくりです。記事を繰り返すのではなく、最初の自分に実際に伝えたいことを、それぞれを学ぶのにかかったコスト順に並べました。
共通する糸は居心地の悪いものです:これらの失敗のほとんどは、自ら名乗り出ませんでした。 それらはもっともらしい数値、正しく見える注文、正常に見える画面を生み出しました。誰かのお金を扱うシステムでは、例外を投げるバグは優しい方です。
要点
- サードパーティAPIは静かに失敗します。要求したより少ないデータを運ぶHTTP 200こそ、設計で備えるべき失敗モードであり、500ではありません。
- シミュレーターがシミュレートするものをテストする前に、シミュレーター自体をテストしてください。壊れたシミュレーターは、正常なものとまったく同じに見える数値を返します。
- シミュレートできなかったものを報告してください。明示されたギャップを伴う結果は、条件を静かに捨てたきれいに見える結果よりも価値があります。
- 精度はユーティリティ関数ではなく、1つの領域です。ステップサイズ、ティックサイズ、最小値は、ペアごと、取引所ごと、市場タイプごとに異なります。
- 制約を早く選んでください。ユーザーの資金を決して預からないと決めたことは、問題のカテゴリー全体を解決する代わりに消し去りました。
- お金のインターフェースでは、プラットフォームが編集として扱うジェスチャーを監査してください。フォーカスされた数値入力上のマウスホイールはその1つです。
1. すべてのAPIは時々、間違ったまま成功すると想定する
私がした最も高くついた思い込みは、失敗したリクエストは失敗のように見えるだろうというものでした。
負荷のかかった取引所は、要求より少ないローソク足を伴うHTTP 200を返し、エラーフィールドも警告もありません。私たちのディープバックテストの1つは約536,000本のローソク足を要求し、58,000本を受け取りました。同じリクエストが1時間後には完全なセットを返しました。レスポンスの中に、この2つを区別するものは何もありませんでした。
チェックしていなければ、エンジンは意図した履歴のごく一部で戦略をシミュレートし、自信ありげな数値を報告します。それはクラッシュより悪いです。なぜならクラッシュは正直だからです。
そこから2つのルールが生まれました:ステータスコードだけでなく、成功レスポンスの形を検証すること、そして何をするか決める前に、一時的な失敗と恒久的な失敗を区別すること。この2つは発生した瞬間には同じに見えますが、正反対の対応に値します。
2. 戦略ではなく、シミュレーターをテストする
あらゆる本能が戦略ロジックのテストへとあなたを押しやります。なぜならそれが面白い部分だからです。罠は、壊れたシミュレーターが正常なものと区別できない出力を生み出すことです。データの10分の1を静かに処理した実行でも、数値は返ってきます。退出が一度も評価されなかった実行は、怪しいほど平坦な数値を返します。
これを直した転換は、戦略が変えられないものに対してアサーションを書くことでした:処理されたローソク足が取得されたローソク足と一致すること、既知の期間にわたる実行が実際にその期間をカバーすること、トリガーが保証された設定が取引を生み出すこと。
それらの不変条件が保たれているとき、奇妙な結果は本物の発見です。保たれていないとき、その結果はスーツを着たノイズです。
3. シミュレートできなかったものを報告する
これはバグというより設計上の選択であり、最も過小評価されているものだと私は思います。
再生できない条件があります。外部のwebhookシグナルには履歴の記録がありません。誘惑に駆られる動きは、それをスキップして残りを評価することであり、それは出力を完全に見せます。
それがAかつBを必要とする戦略に何をするか見てみましょう。Bをシミュレートできない場合、Aだけが判断し、シミュレートされたボットは、実際のボットなら見送っていた場所でエントリーします。この誤差はランダムではありません:ANDロジックの下で条件を1つ捨てると、現実より多い取引しか生み出せません。だからバイアスは毎回、見栄えのよい結果を指し示します。
私たちはシミュレーションを実行し続けましたが、結果には何がスキップされたかを名指しする明示的な警告が付いています。大声で失敗できないシミュレーターは静かに失敗します。そして数値を生み出すものにおける静かな失敗は、存在する中で最悪の失敗モードです。
4. 滑らかなエクイティカーブは答えではなく、問いである
関連していますが、コードではなく人間を欺くため、切り分ける価値があります。
損切りを設定しないDCA戦略(セーフティオーダーの階段)は、ほとんど損失を実現しません。保有し、買い増します。だからクローズした取引はほぼすべて勝ちであり、勝率は素晴らしく見え、エクイティカーブはきれいな階段になります。
リスクはどこにも消えていません。それは先送りされただけで、その先送りには厳格な限界があります:さらなるセーフティオーダーのために残された資本です。有用な問いは「ドローダウンはいくらだったか」ではなく、「価格がこれに逆らい続けたら、どの時点で戦略は余地を使い果たすか」です。
ドローダウンそのものにも同じ懐疑が必要です。それはピーク時の割り当て資本に対して測定されるので、同じ200 USDTの損失が、500 USDTの割り当てでは40%、5,000では4%と表示されます。同じように取引する2つのボットが、まったく異なる数値を表示することがあります。
5. 精度はヘルパーではなく、1つの領域である
私は「数量を有効なステップに丸める」を1つのユーティリティ関数として片付けました。それは作業のカテゴリーであり、ミスがお金を失わせる場所に潜んでいます。
浮動小数点がその始まりです:0.29を0.01のステップでスケーリングすると28.999999999999996になり、これは静かに、より小さな注文の方向へ、まるまる1ステップ低く切り捨てられます。
さらに、取引所どうしがルールそのものについて一致しません。ある取引所はUSDTでの注文額をチェックし、別の取引所は金額チェックをまったくせずに契約数をチェックし、また別の取引所は両方をチェックします。この領域での私たちの最悪のバグは、ある取引所には存在しない最小値をでっち上げ、それに照らして有効な注文を拒否したことから生まれました。振り返ってみれば、その手がかりは、私たちの制約バージョンが価格に依存していたのに対し、本物はそうではなかったことでした。
取引所がペアごとに定義するものに対して単一の定数を書くところではどこでも、あなたは時限式のバグを書いていることになります。
6. 制約を早く選ぶ
最後のものは間違いではありません。それは、良い意味でその結果を過小評価していた決定です。
Freyaはユーザーの取引資金を決して預かりません。APIキーは読み取りと取引の権限を持ちますが、出金権限は決して持ちません。そして出金権限付きで届いたキーは、受け入れて無視するのではなく、拒否されます。この区別は聞こえる以上に重要です:「私たちは出金しません」はユーザーが検証できない私たちの行動についての主張ですが、「キーは出金できない」は取引所によって強制され、ユーザーが自分の設定で確認できます。
私はこれをマーケティングのポイントだと予想していました。実際にはアーキテクチャ上のものであり、システムをより小さくしました:カストディ台帳なし、突合なし、出金キューなし、取引資本のためのコールドストレージポリシーなし。金融ソフトウェアで最も難しい問題のカテゴリー全体が存在しないのは、それらを生み出すものを私たちが決して引き受けなかったからです。
それに取って代わるものは、より狭く鋭いものです:システムはリアルタイムで正しくなければなりません。なぜなら何も取り消せないからです。 誰か他人の取引所口座で約定した注文は、最終的なものです。
必要になると思っていなかったもの
おまけです。なぜなら最も驚かされたからです:お金のインターフェースでは、フロントエンドはエンジンと同じ偏執が必要です。
フォーカスされた<input type="number">は、その上でホイールをスクロールすると値が増減します。数量ピッカーでは、それは煩わしさです。レバレッジ、注文サイズ、価格では、ユーザーが選んだものを静かに書き換え、それでもフォームは検証を通ります。そのバグについて、スクリーンショットに見えるものは何もありません。
すべてを1行に圧縮するなら
自ら名乗り出ない失敗のために作ってください。例外を投げるものは、自分の力であなたを見つけ出します。
