HuobiとHTX: 1日の一部だけ失敗する署名タイムスタンプの修正 | eSeGeCe ブログ

HuobiとHTX: 1日の一部だけ失敗する署名タイムスタンプの修正

· コンポーネント

バグには、常に発生するものと、決まった時間帯にだけ発生するものがあります。2026.9で修正されたHuobiとHTXの署名不具合は後者のタイプで、そのために原因の特定がはるかに困難でした。UTC以外のタイムゾーンで動作するホストでは、1日のうち一部の時間帯だけプライベートリクエストが失敗し、それ以外の時間帯は正常に動作していました。これは、パターンが時計と一致していることに誰かが気づくまでは、断続的な認証エラーとまったく見分けがつかないものでした。

2つの異なる時計から作られたタイムスタンプ

HuobiとHTXはいずれも、署名済みリクエストにyyyy-MM-ddTHH:mm:ss形式のUTCタイムスタンプを含めることを要求します。TsgcWSAPI_HuobiTsgcWSAPI_HTXの両方が共有するTsgcWS_API_Huobi_Base内の署名処理ルーチンは、このタイムスタンプを2つの異なる情報源から組み立てていました。日付部分はローカルのシステム時計から、時刻部分はUTCから取得していたのです。ほとんどのマシンでは1日の大半において、ローカルの日付とUTCの日付は同じ値になるため、問題は表面化しませんでした。しかし、UTCの深夜0時付近では、ローカルのタイムゾーンオフセットによってその境界の反対側に位置するホストの場合、日付と時刻が一致しなくなり、Huobi側で計算された署名と一致しなくなるため、リクエストは拒否されていました。

この修正では、日付と時刻の両方を同じUTC値から取得するようにしています。

uses
  sgcBase_Helpers;

var
  vUTC: TDateTime;
  vTimeStamp: string;
begin
  vUTC := sgcGetDateTimeAsUTC;
  vTimeStamp := FormatDateTime('yyyy-mm-dd', vUTC) + 'T' +
    FormatDateTime('hh:nn:ss', vUTC);
end;

設定すべき項目はありません。TsgcWSAPI_HuobiTsgcWSAPI_HTXはどちらも同じ署名処理ルーチンを呼び出すため、両方が同時に修正されます。

uses
  sgcWebSocket, sgcWebSocket_APIs;

var
  oHuobi: TsgcWSAPI_Huobi;
begin
  oHuobi := TsgcWSAPI_Huobi.Create(nil);
  oHuobi.Client := oClient;
  oHuobi.Huobi.ApiKey := 'your_api_key';
  oHuobi.Huobi.ApiSecret := 'your_api_secret';
  oClient.Active := True;
  // Authentication now signs with a timestamp taken entirely from UTC.
  oHuobi.SubscribeOrderUpdates('btcusdt');
end;

ログにHuobiまたはHTXのプライベートリクエストが、明確な原因もなく断続的に失敗している様子が記録されている場合、特にサーバーがUTCで動作していないのであれば、これがその原因である可能性が非常に高いです。

再接続時にプライベート購読が失われる問題

Huobiは、同じ修正作業で対応された別の再接続の不具合の影響を受けた複数の取引所クライアントの1つでもありました。WatchDogが再接続した後、プライベート購読、つまり注文、残高、約定などが再送信されていなかったのです。再接続自体は成功し、ログにもそのように記録されていたため、切断前に受信していたプライベートフィードが気づかないうちに失われてしまったことを示す手がかりは何もありませんでした。この再送信処理は現在、再接続後に公開市場データの購読を復元する既存の再購読処理の一部として組み込まれています。

アップグレード

どちらの修正もドロップイン形式で適用されます。設定すべきプロパティも、変更すべきコードもありません。署名は単純に正しく計算されるようになり、再接続時の再送信処理にはプライベート購読も含まれるようになりました。

ご質問、フィードバック、移行のお手伝いが必要ですか? お問い合わせください — コードを書いた本人たちから返信が届きます。