
高頻度取引は、迅速な取引実行と市場の微細構造に対する繊細な洞察力に依存する、困難で競争の激しい分野です。多くの注目を集めている戦略の 1 つは、市場の「象」を利用して小さいながらも頻繁に利益を上げることに焦点を当てたペニー ジャンプです。この記事では、初心者でもペニージャンプ戦略の仕組みを理解できるように、戦略コードの詳細を掘り下げながら、ペニージャンプ戦略の仕組みを詳しく説明します。
株式市場において、「象」とは通常、大量の株式を売買したいが市場価格で取引することを望まない機関投資家を指します。代わりに、彼らは自分の意図を示すために、市場に大量の指値注文(保留注文とも呼ばれる)を出すことを選択します。大規模な取引は市場に大きな影響を与える可能性があるため、この行動は市場で広く注目を集めています。
たとえば、ある株の市場深度が元々次のようであったとします: 200 | \(1.01 x \)1.03 | 200。すると、「象」が現れ、1株1.01ドルで3,000株を買う注文を出した。この時点で、市場の深さは 3,200 | \(1.01 x \)1.03 | 200 になります。この行動は、市場の他の参加者の注目の的となる「象」を導入するようなものです。
競争市場 高頻度取引業者の場合、利益は主に市場の微細構造を分析して他のトレーダーの意図を推測することから得られます。象が現れると、高頻度取引業者はすぐにポジションを確立し、わずかな価格変動を捉えようとします。彼らの目標は、短期間で頻繁に取引を行い、小さいながらも累積的な利益を蓄積することです。
ゾウの窮状 象は市場で大規模に取引することを望んでいるかもしれないが、その行動は取引の意図を裏切るものでもあるため、高頻度取引業者の標的となる。高頻度取引業者は、事前にポジションを確立し、価格変動から利益を得ようとします。市場に象が存在すると、競争市場で反応が引き起こされ、取引戦略に影響を及ぼす可能性があります。
市場における欺瞞 現実には、大規模な機関投資家が市場で大量の買い注文や売り注文を露骨に出すことは通常ありません。なぜなら、そのような行動は他の市場参加者に対抗措置を取らせたり、市場を操作したりする恐れがあるからです。そのため、彼らは、高頻度取引業者を市場に誘い込むために虚偽の印象を与え、その後すぐに売買して価格変動から利益を得る戦略を採用する可能性があります。
ペニージャンプ戦略の中心的な考え方は、象が市場に現れて特定の価格(たとえば 1.01 ドル)をサポートすると、高頻度取引業者はすぐに入札価格を 1 セントずつ、たとえば 1.02 ドルまで上げるというものです。これは、高頻度取引業者が、象の出現はその価格レベルで強力な買い支えがあることを意味すると理解しているため、価格が上昇することを期待してそれに従おうとするからです。価格が 1.03 x 1.05 ドルに上昇すると、高頻度取引業者はすぐに売却して 0.01 ドルの利益を得ることができます。
それだけでなく、高頻度取引業者は、価格が上昇しなくても購入後に利益を上げることもできます。彼らは象が底値を支えていることを知っているので、すぐに象に株を売却し、その差額でわずかな利益を得ることができます。
戦略ソースコード: https://www.fmz.com/strategy/358
上記の戦略コードは、ペニージャンプ戦略を実装する例です。初心者でもコードの動作を理解できるように、コードの詳細な説明を以下に示します。
var Counter = {
i: 0,
w: 0,
f: 0
};
// Variables
var InitAccount = null;
function CancelAll() {
while (true) {
var orders = _C(exchange.GetOrders);
if (orders.length == 0) {
break;
}
for (var i = 0; i < orders.length; i++) {
exchange.CancelOrder(orders[i].Id);
}
Sleep(Interval);
}
}
function updateStatus(msg) {
LogStatus("调戏次数:", Counter.i, "成功:", Counter.w, "失败:", Counter.f, "\n"+msg+"#0000ff\n"+new Date());
}
function main() {
if (DisableLog) {
EnableLog(false);
}
CancelAll();
InitAccount = _C(exchange.GetAccount);
Log(InitAccount);
var i = 0;
var locks = 0;
while (true) {
Sleep(Interval);
var depth = _C(exchange.GetDepth);
if (depth.Asks.length === 0 || depth.Bids.length === 0) {
continue;
}
updateStatus("搜索大象中.... 买一: " + depth.Bids[0].Price + ", 卖一:" + depth.Asks[0].Price + ", 锁定次数: " + locks);
var askPrice = 0;
for (i = 0; i < depth.Asks.length; i++) {
if (depth.Asks[i].Amount >= Lot) {
askPrice = depth.Asks[i].Price;
break;
}
}
if (askPrice === 0) {
continue;
}
var elephant = null;
// skip Bids[0]
for (i = 1; i < depth.Bids.length; i++) {
if ((askPrice - depth.Bids[i].Price) > ElephantSpace) {
break;
}
if (depth.Bids[i].Amount >= ElephantAmount) {
elephant = depth.Bids[i];
break;
}
}
if (!elephant) {
locks = 0;
continue;
}
locks++;
if (locks < LockCount) {
continue;
}
locks = 0;
updateStatus("调戏大象中....大象在第" + i + "档, " + JSON.stringify(elephant));
exchange.Buy(elephant.Price + PennyTick, Lot, "Bids[" + i + "]", elephant);
var ts = new Date().getTime();
while (true) {
Sleep(CheckInterval);
var orders = _C(exchange.GetOrders);
if (orders.length == 0) {
break;
}
if ((new Date().getTime() - ts) > WaitInterval) {
for (var i = 0; i < orders.length; i++) {
exchange.CancelOrder(orders[i].Id);
}
}
}
var account = _C(exchange.GetAccount);
var opAmount = _N(account.Stocks - InitAccount.Stocks);
if (opAmount < 0.001) {
Counter.f++;
Counter.i++;
continue;
}
updateStatus("买单得手: " + opAmount +", 开始出手...");
exchange.Sell(elephant.Price + (PennyTick * ProfitTick), opAmount);
var success = true;
while (true) {
var depth = _C(exchange.GetDepth);
if (depth.Bids.length > 0 && depth.Bids[0].Price <= (elephant.Price-(STTick*PennyTick))) {
success = false;
updateStatus("没有得手, 开始止损, 当前买一: " + depth.Bids[0].Price);
CancelAll();
account = _C(exchange.GetAccount);
var opAmount = _N(account.Stocks - InitAccount.Stocks);
if (opAmount < 0.001) {
break;
}
exchange.Sell(depth.Bids[0].Price, opAmount);
}
var orders = _C(exchange.GetOrders);
if (orders.length === 0) {
break;
}
Sleep(CheckInterval);
}
if (success) {
Counter.w++;
} else {
Counter.f++;
}
Counter.i++;
var account = _C(exchange.GetAccount);
LogProfit(account.Balance - InitAccount.Balance, account);
}
}
提供された戦略コードを 1 行ずつ確認して、その仕組みをより詳細に理解できるようにします。
var Counter = {
i: 0,
w: 0,
f: 0
};
このコードは、戦略の取引統計を追跡するために使用される Counter というオブジェクトを初期化します。具体的には、次の 3 つの属性が含まれます。
これらの属性は、ポリシー実行中に記録および更新されます。
var InitAccount = null;
このコード行は、戦略の実行開始時にアカウント情報を格納する InitAccount という変数を初期化します。
function CancelAll() {
while (true) {
var orders = _C(exchange.GetOrders);
if (orders.length == 0) {
break;
}
for (var i = 0; i < orders.length; i++) {
exchange.CancelOrder(orders[i].Id);
}
Sleep(Interval);
}
}
これはCancelAll()この機能の目的は、市場にあるすべての未決済注文をキャンセルすることです。その機能を段階的に説明しましょう:
while (true): これは未処理の注文がなくなるまで実行される無限ループです。var orders = _C(exchange.GetOrders): このコード行は exchange.GetOrders 関数を使用して現在のアカウントのすべての保留中の注文を取得し、それらを orders 変数に保存します。if (orders.length == 0): このコード行は、未処理の注文があるかどうかを確認します。注文配列の長さが 0 の場合、未処理の注文がないことを意味し、ループは中断されます。for (var i = 0; i < orders.length; i++): これは、すべての未処理の注文を反復処理する for ループです。exchange.CancelOrder(orders[i].Id): このコード行は exchange.CancelOrder() 関数を使用して、注文 ID ごとに各注文をキャンセルします。Sleep(Interval): このコード行は待機サイクルを導入し、注文のキャンセル操作が頻繁に行われないように、一定期間 (ミリ秒単位) 待機します。この機能の目的は、メイン戦略を実行する前に未処理の注文が存在しないことを確認し、メイン戦略の実行を妨げないようにすることです。
function updateStatus(msg) {
LogStatus("调戏次数:", Counter.i, "成功:", Counter.w, "失败:", Counter.f, "\n" + msg + "#0000ff\n" + new Date());
}
これはupdateStatus(msg)取引ステータス情報を更新し記録する機能。これは、通常、現在の市場状況に関する情報を含む msg パラメータを受け入れます。関数の具体的な操作は次のとおりです。
使用LogStatus()この関数は、戦略の実行中にステータス バーに表示される情報を記録します。トランザクションの数、成功、失敗に関するテキストが表示されます。
添付msg現在の市場状況に関する情報を含むパラメータ。
現在のタイムスタンプが追加されます(new Date()) をクリックすると時間情報が表示されます。
この機能の目的は、戦略実行中の監視と分析のために取引ステータス情報を記録および更新することです。
function main() {
if (DisableLog) {
EnableLog(false);
}
CancelAll();
InitAccount = _C(exchange.GetAccount);
Log(InitAccount);
var i = 0;
var locks = 0;
while (true) {
Sleep(Interval);
var depth = _C(exchange.GetDepth);
if (depth.Asks.length === 0 || depth.Bids.length === 0) {
continue;
}
updateStatus("搜索大象中.... 买一: " + depth.Bids[0].Price + ", 卖一:" + depth.Asks[0].Price + ", 锁定次数: " + locks);
var askPrice = 0;
for (i = 0; i < depth.Asks.length; i++) {
if (depth.Asks[i].Amount >= Lot) {
askPrice = depth.Asks[i].Price;
break;
}
}
if (askPrice === 0) {
continue;
}
var elephant = null;
// skip Bids[0]
for (i = 1; i < depth.Bids.length; i++) {
if ((askPrice - depth.Bids[i].Price) > ElephantSpace) {
break;
}
if (depth.Bids[i].Amount >= ElephantAmount) {
elephant = depth.Bids[i];
break;
}
}
if (!elephant) {
locks = 0;
continue;
}
locks++;
if (locks < LockCount) {
continue;
}
locks = 0;
updateStatus("调戏大象中....大象在第" + i + "档, " + JSON.stringify(elephant));
exchange.Buy(elephant.Price + PennyTick, Lot, "Bids[" + i + "]", elephant);
var ts = new Date().getTime();
while (true) {
Sleep(CheckInterval);
var orders = _C(exchange.GetOrders);
if (orders.length == 0) {
break;
}
if ((new Date().getTime() - ts) > WaitInterval) {
for (var i = 0; i < orders.length; i++) {
exchange.CancelOrder(orders[i].Id);
}
}
}
var account = _C(exchange.GetAccount);
var opAmount = _N(account.Stocks - InitAccount.Stocks);
if (opAmount < 0.001) {
Counter.f++;
Counter.i++;
continue;
}
updateStatus("买单得手: " + opAmount +", 开始出手...");
exchange.Sell(elephant.Price + (PennyTick * ProfitTick), opAmount);
var success = true;
while (true) {
var depth = _C(exchange.GetDepth);
if (depth.Bids.length > 0 && depth.Bids[0].Price <= (elephant.Price-(STTick*PennyTick))) {
success = false;
updateStatus("没有得手, 开始止损, 当前买一: " + depth.Bids[0].Price);
CancelAll();
account = _C(exchange.GetAccount);
var opAmount = _N(account.Stocks - InitAccount.Stocks);
if (opAmount < 0.001) {
break;
}
exchange.Sell(depth.Bids[0].Price, opAmount);
}
var orders = _C(exchange.GetOrders);
if (orders.length === 0) {
break;
}
Sleep(CheckInterval);
}
if (success) {
Counter.w++;
} else {
Counter.f++;
}
Counter.i++;
var account = _C(exchange.GetAccount);
LogProfit(account.Balance - InitAccount.Balance, account);
}
}
これは戦略の主な実行機能であるmain()、戦略の中核となるロジックが含まれています。動作を1行ずつ説明してみましょう。
if (DisableLog): このコード行は、DisableLog 変数が true かどうかを確認し、true の場合はログ記録を無効にします。これは、ポリシーが不要な情報をログに記録しないようにするためです。
CancelAll(): 前に説明したCancelAll()関数を呼び出して、未完了の注文が存在しないことを確認します。
InitAccount = _C(exchange.GetAccount): このコード行は現在のアカウント情報を取得し、それを InitAccount 変数に保存します。これは、戦略の実行が開始されたときのアカウントの状態を記録するために使用されます。
var i = 0; そして var locks = 0;: 後続の戦略ロジックで使用される 2 つの変数 i と locks を初期化します。
while (true): これは無限ループであり、主に戦略の継続的な実行に使用されます。
次に、1行ずつ説明しますwhile (true)ループ内の主な戦略ロジック。
while (true) {
Sleep(Interval);
var depth = _C(exchange.GetDepth);
if (depth.Asks.length === 0 || depth.Bids.length === 0) {
continue;
}
updateStatus("搜索大象中.... 买一: " + depth.Bids[0].Price + ", 卖一:" + depth.Asks[0].Price + ", 锁定次数: " + locks);
Sleep(Interval): このコード行により、戦略を一定期間スリープさせて、戦略の実行頻度を制御できるようになります。 Interval パラメータは、スリープ間隔をミリ秒単位で定義します。
var depth = _C(exchange.GetDepth): 売り注文と買い注文の価格と数量を含む現在の市場深度情報を取得します。この情報は depth 変数に保存されます。
if (depth.Asks.length === 0 || depth.Bids.length === 0): このコード行は、市場の深さ情報をチェックして、売り注文と買い注文の両方が存在することを確認します。いずれか 1 つが存在しない場合は、市場に十分な取引情報がない可能性があり、戦略は待機を継続することを意味します。
updateStatus("搜索大象中.... 买一: " + depth.Bids[0].Price + ", 卖一:" + depth.Asks[0].Price + ", 锁定次数: " + locks): このコード行は、updateStatus 関数を呼び出して、戦略のステータス情報を更新します。入札価格、売り価格、以前のロック数など、現在の市場状況を記録します。
var askPrice = 0;
for (i = 0; i < depth.Asks.length; i++) {
if (depth.Asks[i].Amount >= Lot) {
askPrice = depth.Asks[i].Price;
break;
}
}
if (askPrice === 0) {
continue;
}
var elephant = null;
var askPrice = 0;: 条件を満たす売り注文価格を格納するために使用される askPrice 変数を初期化します。
for (i = 0; i < depth.Asks.length; i++): これは、市場売り注文の価格と数量の情報を反復処理するために使用される for ループです。
if (depth.Asks[i].Amount >= Lot): ループ内で、各売り注文の数量が指定されたロット以上であるかどうかを確認します。そうであれば、売り注文の価格を askPrice に保存し、ループを終了します。
if (askPrice === 0): 満足のいく売り注文が見つからない場合(askPrice がまだ 0 の場合)、戦略は待機を継続し、後続の操作をスキップします。
var elephant = null;: 「elephant」として識別される購入注文情報を格納するために使用される elephant 変数を初期化します。
for (i = 1; i < depth.Bids.length; i++) {
if ((askPrice - depth.Bids[i].Price) > ElephantSpace) {
break;
}
if (depth.Bids[i].Amount >= ElephantAmount) {
elephant = depth.Bids[i];
break;
}
}
if (!elephant) {
locks = 0;
continue;
}
locks++;
if (locks < LockCount) {
continue;
}
locks = 0;
最初の買い注文(入札)をスキップして、市場の買い注文の価格と数量情報を反復処理し続けます。[0])。
if ((askPrice - depth.Bids[i].Price) > ElephantSpace): 現在の購入価格と売り価格の差が ElephantSpace より大きいかどうかを確認します。もしそうなら、それは「象」から十分に離れていることを意味し、戦略は検索を継続しません。
if (depth.Bids[i].Amount >= ElephantAmount): 現在の購入注文額が ElephantAmount 以上かどうかを確認します。 そうである場合は、購入注文情報を elephant 変数に保存します。
if (!elephant): 「象」が見つからない場合は、ロックカウントを 0 にリセットして待機を続けます。
locks++: 「象」が見つかった場合、ロックの数が増加します。これは、「象」の存在が一定期間にわたって複数回確認された後に戦略が実行されることを確認するためです。
if (locks < LockCount): ロック数が要件 (LockCount) に達しているかどうかを確認します。要件が満たされていない場合は、引き続き待機してください。 updateStatus("调戏大象中....大象在第" + i + "档, " + JSON.stringify(elephant));
exchange.Buy(elephant.Price + PennyTick, Lot, "Bids[" + i + "]", elephant);
var ts = new Date().getTime();
while (true) {
Sleep(CheckInterval);
var orders = _C(exchange.GetOrders);
if (orders.length == 0) {
break;
}
if ((new Date().getTime() - ts) > WaitInterval) {
for (var i = 0; i < orders.length; i++) {
exchange.CancelOrder(orders[i].Id);
}
}
}
updateStatus("调戏大象中....大象在第" + i + "档, " + JSON.stringify(elephant)): updateStatus 関数を呼び出して、見つかった「象」のギア位置や関連情報など、戦略の現在のステータスを記録します。これはポリシーのステータス列に表示されます。
exchange.Buy(elephant.Price + PennyTick, Lot, "Bids[" + i + "]", elephant): exchange.Buy 関数を使用して、見つかった「象」を購入します。購入価格はelephant.Price + PennyTick、購入数量はLot、購入操作は「Bids」と記述されます。[” + i + “]“。
var ts = new Date().getTime(): 後続の時間間隔の計算のために現在の時刻のタイムスタンプを取得します。
while (true): 新しい無限ループを入力して、「エレファント」買い注文の実行を待機します。
Sleep(CheckInterval): 注文ステータスをチェックする頻度を制御するために、戦略は一定期間スリープします。
var orders = _C(exchange.GetOrders): 現在のアカウントのすべての注文情報を取得します。
if (orders.length == 0): 未完了の注文があるかどうかを確認し、ない場合はループから抜けます。
(new Date().getTime() - ts) > WaitInterval: 現在の時刻と「象」が購入された時刻との間の時間間隔を計算します。WaitInterval を超える場合は、待機がタイムアウトしたことを意味します。
for (var i = 0; i < orders.length; i++): 未完了の注文をすべて反復処理します。
exchange.CancelOrder(orders[i].Id): exchange.CancelOrder 関数を使用して、各オープン注文をキャンセルします。
var account = _C(exchange.GetAccount);
var opAmount = _N(account.Stocks - InitAccount.Stocks);
if (opAmount < 0.001) {
Counter.f++;
Counter.i++;
continue;
}
updateStatus("买单得手: " + opAmount + ", 开始出手...");
exchange.Sell(elephant.Price + (PennyTick * ProfitTick), opAmount);
var success = true;
while (true) {
var depth = _C(exchange.GetDepth);
if (depth.Bids.length > 0 && depth.Bids[0].Price <= (elephant.Price - (STTick * PennyTick))) {
success = false;
updateStatus("没有得手, 开始止损, 当前买一: " + depth.Bids[0].Price);
CancelAll();
account = _C(exchange.GetAccount);
var opAmount = _N(account.Stocks - InitAccount.Stocks);
if (opAmount < 0.001) {
break;
}
exchange.Sell(depth.Bids[0].Price, opAmount);
}
var orders = _C(exchange.GetOrders);
if (orders.length === 0) {
break;
}
Sleep(CheckInterval);
}
if (success) {
Counter.w++;
} else {
Counter.f++;
}
Counter.i++;
var account = _C(exchange.GetAccount);
LogProfit(account.Balance - InitAccount.Balance, account);
}
var account = _C(exchange.GetAccount): 現在のアカウント情報を取得します。
var opAmount = _N(account.Stocks - InitAccount.Stocks):「Elephant」購入後の口座内資産の変化を計算します。変化が 0.001 未満の場合、購入は失敗したことを意味し、失敗回数が増加し、次のサイクルが継続されます。
updateStatus("买单得手: " + opAmount + ", 开始出手..."): 購入数量を含む「象」の購入成功情報を記録します。
exchange.Sell(elephant.Price + (PennyTick * ProfitTick), opAmount): exchange.Sell 関数を使用して、正常に購入した「象」を販売して利益を上げます。販売価格は、elephant.Price + (PennyTick * ProfitTick) です。
売り注文の実行を待機する新しい無限ループに入ります。
var depth = _C(exchange.GetDepth): 市場の深さに関する情報を取得します。
if (depth.Bids.length > 0 && depth.Bids[0].Price <= (elephant.Price - (STTick * PennyTick))): マーケットデプス情報を確認し、マーケット価格がストップロス価格まで下がった場合は、ストップロス操作を実行します。
CancelAll(): ポジションリスクを回避するために、CancelAll() 関数を呼び出して、未完了の注文をすべてキャンセルします。
if (opAmount < 0.001): 購入数量を再度確認します。0.001 未満の場合、購入が失敗したことを意味し、ループが終了します。
exchange.Sell(depth.Bids[0].Price, opAmount): ストップロス操作を実行し、残りの資産を現在の市場最低価格で売却します。
最後に、取引が成功したかどうかに応じて、成功数と失敗数が更新され、取引利益が記録されます。
これは戦略全体の詳細な説明です。この戦略の核となる考え方は、市場で「象」(大量の買い注文)を探し、それを買って、わずかな利益で売ることです。これには、購入数量 (Lot)、エラー再試行間隔 (Interval)、象レベル (ElephantAmount)、象距離 (ElephantSpace) など、戦略の動作を調整するためのいくつかの重要なパラメータが含まれています。
一般的に、この戦略は、市場の深さの情報を活用し、大規模な買い注文を識別し、短期間で売買取引を実行することを目的とした高頻度取引戦略です。小さな利益を素早く得るためには、常に市場を監視し、売買操作を実行する必要があります。しかし、市場の変動に迅速に対応し、大きな損失を回避するためのリスク管理とストップロスのメカニズムも考慮する必要があるため、これは高リスクの戦略でもあります。
この戦略は特定の市場と取引プラットフォームに基づいており、異なる市場や取引所に合わせて適切に調整および最適化する必要がある場合があることに注意してください。実際の適用においては、投資家は戦略のパフォーマンスを慎重にテストして評価し、それが投資目的とリスク許容度と一致していることを確認する必要があります。
戦略の実行を続けると、ループが継続され、次の処理が実行されます。
まず、この戦略は市場の深さの情報をチェックして、現在の売り注文と買い注文を把握します。
次に、この戦略は、売り注文の数量がロット以上である条件を満たす売り注文を見つけようとします。条件を満たす売り注文が見つかった場合、売り注文価格がaskPriceとして記録されます。
その後、この戦略は「象」(大量購入注文)を探し続けます。市場内の買い注文を反復処理し、最初の買い注文 (通常は最も価格の高い買い注文) をスキップします。条件を満たす「象」が見つかった場合、「象」の情報を記録し、ロックの数を増やしていきます。
十分な数の「象」が連続して見つかった場合 (LockCount パラメータによって制御されます)、戦略はさらに次の操作を実行します。
全体的な戦略は、上記の操作を継続的に繰り返して、できるだけ多くの「象」を捕獲し、わずかな利益を獲得することです。これは、資本を保護するためにリスク管理とストップロスのメカニズムを考慮しながら、市場の変化に迅速に対応する必要がある高頻度取引戦略です。投資家は、特に変動の激しい市場では、この戦略の使用を慎重に検討する必要があります。
ペニージャンプ戦略は、高頻度取引の典型的な例であり、市場参加者間の微妙なゲームと競争を示しています。この戦略は、ボラティリティが高く、機関投資家や高頻度取引業者が短期間で利益を得ようとしている暗号通貨市場で特に顕著です。しかし、これにより市場は困難になり、競争上の優位性を維持するために戦略を絶えず適応および調整する必要が生じます。この熾烈な競争の世界では、市場の微細構造を観察し、迅速に対応できるトレーダーだけが成功するでしょう。