Type/to search
8
Follow
1364
Followers
暗号通貨先物のためのマーチンゲール戦略設計
Discussions
Created 2021-07-02 14:35:34  Updated 2023-09-21 21:09:56
 22
 6556

img

暗号通貨先物のためのマーチンゲール戦略設計

最近、FMZ公式グループではマーチンゲール戦略に関する議論が多く行われていますが、プラットフォーム上のデジタル通貨契約に関するマーチンゲール戦略はあまりありません。そこで、私はこの機会を利用して、暗号通貨先物のためのシンプルなマーチンゲール戦略を設計しました。なぜマーティン型戦略と呼ばれるのでしょうか? マーティン戦略の潜在的なリスクは確かに小さくなく、マーティン戦略に完全に従って設計されていないためです。ただし、このタイプの戦略には依然としてかなりのリスクがあり、マーチンゲール戦略のパラメータ設定はリスクと密接に関連しているため、リスクを無視してはなりません。

この記事は主にマーティン型戦略の設計について説明し、そこから学びます。戦略のアイデア自体は非常に明確です。FMZ のユーザーとして、私たちは戦略設計をより重視します。

総資産を取得する

デジタル通貨先物戦略を設計する際には、総株式データがよく使用されます。特に変動収益を計算する必要がある場合、収益を計算する必要があるためです。オープンポジションは証拠金を占有するため、保留中の注文も証拠金を占有します。このとき、FMZプラットフォームのAPIインターフェースを呼び出すexchange.GetAccount()取得されるのは、利用可能な資産と保留中の注文によって凍結された資産です。実際、ほとんどのデジタル通貨先物取引所は総資産に関するデータを提供していますが、FMZ はこの属性を統一的にカプセル化していません。

したがって、さまざまな取引所に応じてこのデータを取得するための関数を設計します。

// OKEX V5 获取总权益 function getTotalEquity_OKEX_V5() { var totalEquity = null var ret = exchange.IO("api", "GET", "/api/v5/account/balance", "ccy=USDT") if (ret) { try { totalEquity = parseFloat(ret.data[0].details[0].eq) } catch(e) { Log("获取账户总权益失败!") return null } } return totalEquity } // 币安期货 function getTotalEquity_Binance() { var totalEquity = null var ret = exchange.GetAccount() if (ret) { try { totalEquity = parseFloat(ret.Info.totalWalletBalance) } catch(e) { Log("获取账户总权益失败!") return null } } return totalEquity }

コードではtotalEquityこれが私たちが必要とする総資本です。次に、呼び出しエントリとして関数を記述し、交換名に従って対応する関数を呼び出します。

function getTotalEquity() { var exName = exchange.GetName() if (exName == "Futures_OKCoin") { return getTotalEquity_OKEX_V5() } else if (exName == "Futures_Binance") { return getTotalEquity_Binance() } else { throw "不支持该交易所" } }

ヘルパー関数を設計する

メイン関数とメインロジックを設計する前に。まだ準備と補助機能の設計が必要です。

  • 現在保留中の注文をすべてキャンセルする

    function cancelAll() { while (1) { var orders = _C(exchange.GetOrders) if (orders.length == 0) { break } for (var i = 0 ; i < orders.length ; i++) { exchange.CancelOrder(orders[i].Id, orders[i]) Sleep(500) } Sleep(500) } }

    FMZ Strategy Square の戦略サンプルコードをよく見ている人は、この機能をよく知っていると思います。多くの戦略で同様の設計が使用されています。その機能は、保留中の注文の現在のリストを取得し、それらを 1 つずつキャンセルすることです。

  • 先物注文操作

    function trade(distance, price, amount) { var tradeFunc = null if (distance == "buy") { tradeFunc = exchange.Buy } else if (distance == "sell") { tradeFunc = exchange.Sell } else if (distance == "closebuy") { tradeFunc = exchange.Sell } else { tradeFunc = exchange.Buy } exchange.SetDirection(distance) return tradeFunc(price, amount) } function openLong(price, amount) { return trade("buy", price, amount) } function openShort(price, amount) { return trade("sell", price, amount) } function coverLong(price, amount) { return trade("closebuy", price, amount) } function coverShort(price, amount) { return trade("closesell", price, amount) }

    先物取引には、ロングポジションを開く (openLong)、ショートポジションを開く (openShort)、ロングポジションをクローズする (coverLong)、ショートポジションをクローズする (coverShort) の 4 つの方向があります。そこで、これらの操作に対応する 4 つの順序関数を設計しました。注文することだけを考える場合、方向、注文価格、注文数量など、いくつかの要素が必要です。
    そこで、次のようなプログラムも設計しました。trade処理する関数方向(distance)下单价格(price)下单量(amount)すべての操作は明確です。
    ロングポジションを開く(openLong)、ショートポジションを開く(openShort)、ロングポジションを閉じる(coverLong)、ショートポジションを閉じる(coverShort)の関数呼び出しは、最終的に次のように実行されます。tradeこの機能は、確立された方向、価格、数量に従って先物取引所に注文を出すという実際の機能を実行します。

主な機能

戦略は非常にシンプルです。現在の価格を基準として、現在の価格の上下に一定の距離を置いて売り注文(ショート)と買い注文(ロング)を出します。片側が執行されると、残りの注文はすべてキャンセルされ、その後、ポジション価格に基づいて一定の距離で新しい決済注文が配置され、更新された現在の価格で増加注文が配置されますが、増加注文は注文数量が2倍にはなりません。

  • 初期作業
    注文を行う必要があるため、注文 ID を記録するための 2 つのグローバル変数が必要です。

    var buyOrderId = null var sellOrderId = null

    次に、OKEX_V5 シミュレーション ディスクを使用するオプションが戦略インターフェイス パラメータに設計されているため、コード内でいくつかの処理を実行する必要があります。

    var exName = exchange.GetName() // 切换OKEX V5模拟盘 if (isSimulate && exName == "Futures_OKCoin") { exchange.IO("simulate", true) }

    インターフェース パラメータにはすべての情報をリセットするオプションも含まれているため、コードにも対応する処理が必要です。

    if (isReset) { _G(null) LogReset(1) LogProfitReset() LogVacuum() Log("重置所有数据", "#FF0000") }

    私たちは永久契約のみを実行するため、ここではハードコードされており、永久契約のみに設定されています。

    exchange.SetContractType("swap")

    次に、注文価格と注文数量の精度も考慮する必要があります。精度が適切に設定されていない場合、戦略計算プロセス中に精度が失われます。データに小数点以下の桁数が多いと、注文が簡単に交換インターフェースによって拒否されました。

    exchange.SetPrecision(pricePrecision, amountPrecision) Log("设置精度", pricePrecision, amountPrecision)

    シンプルなデータ復旧機能

    if (totalEq == -1 && !IsVirtual()) { var recoverTotalEq = _G("totalEq") if (!recoverTotalEq) { var currTotalEq = getTotalEquity() if (currTotalEq) { totalEq = currTotalEq _G("totalEq", currTotalEq) } else { throw "获取初始权益失败" } } else { totalEq = recoverTotalEq } }

    戦略を実行する際に初期の総口座残高を指定したい場合は、パラメータを設定することができます。totalEqこのパラメータが-1に設定されている場合、戦略は保存された総資産データを読み取ります。保存された総資産データがない場合、現在読み取られている総資産が戦略実行中の初期総資産として使用されます。資本金が増加するということは、利益を得たが資本金の合計が減ったということを意味します。これは損失を出したことを意味します。総資産データが読み取られた場合は、このデータを使用して実行を続行します。

  • メインロジック
    初期作業が完了した後、ようやく戦略の主なロジックにたどり着きました。説明の便宜上、コードコメントに直接説明を書き込みました。

    while (1) { // 策略主要逻辑设计为一个死循环 var ticker = _C(exchange.GetTicker) // 首先读取当前行情信息,主要用到最新成交价 var pos = _C(exchange.GetPosition) // 读取当前持仓数据 if (pos.length > 1) { // 判断持仓数据,由于这个策略的逻辑,是不太可能同时出现多空持仓的,所以发现同时出现多空持仓就抛出错误 Log(pos) throw "同时有多空持仓" // 抛出错误,让策略停止 } // 根据状态而定 if (pos.length == 0) { // 根据持仓状态做出不同操作,pos.length == 0是当没有持仓时 // 未持仓了,统计一次收益 if (!IsVirtual()) { var currTotalEq = getTotalEquity() if (currTotalEq) { LogProfit(currTotalEq - totalEq, "当前总权益:", currTotalEq) } } buyOrderId = openLong(ticker.Last - targetProfit, amount) // 挂开多仓的买单 sellOrderId = openShort(ticker.Last + targetProfit, amount) // 挂开空仓的卖单 } else if (pos[0].Type == PD_LONG) { // 有多头持仓,挂单位置、数量有所不同 var n = 1 var price = ticker.Last buyOrderId = openLong(price - targetProfit * n, amount) sellOrderId = coverLong(pos[0].Price + targetProfit, pos[0].Amount) } else if (pos[0].Type == PD_SHORT) { // 有空头持仓,挂单位置、数量有所不同 var n = 1 var price = ticker.Last buyOrderId = coverShort(pos[0].Price - targetProfit, pos[0].Amount) sellOrderId = openShort(price + targetProfit * n, amount) } if (!sellOrderId || !buyOrderId) { // 如果有一边挂单失败就取消所有挂单,重来 cancelAll() buyOrderId = null sellOrderId = null continue } while (1) { // 挂单完成,开始监控订单 var isFindBuyId = false var isFindSellId = false var orders = _C(exchange.GetOrders) for (var i = 0 ; i < orders.length ; i++) { if (buyOrderId == orders[i].Id) { isFindBuyId = true } if (sellOrderId == orders[i].Id) { isFindSellId = true } } if (!isFindSellId && !isFindBuyId) { // 检测到买卖单都成交了 cancelAll() break } else if (!isFindBuyId) { // 检测到买单成交 Log("买单成交") cancelAll() break } else if (!isFindSellId) { // 检测到卖单成交 Log("卖单成交") cancelAll() break } LogStatus(_D()) Sleep(3000) } Sleep(500) }

全体のロジックと設計が説明されています。

バックテスト

5月19日の市場状況を戦略で体験してみましょう。

img

img

マーチンゲール戦略には依然として一定のリスクがあることがわかります。

実際の取引には OKEX V5 デモをお試しいただけます。

img

戦略アドレス: https://www.fmz.com/strategy/294957

攻略法は主に学習用なので、リアルマネーを使う際は注意して使ってくださいね~!

Related Recommendations
Comment
All comments (20)

    梦大,想要請問這句
    if (!isFindSellId && !isFindBuyId) { // 检测到买卖单都成交了
    偵測訂單時,若快速上下插針同時成交了買賣單,那是否會拋出錯誤?

    4 years ago

    不会抛出错误。依然会取消所有挂单,跳出当前循环,然后继续挂单逻辑。瞬间都成交了就相当于吃到价差利润了。

    4 years ago

    另外就是合约的模式是全仓还是逐仓怎么设定?目前是啥模式呢

    5 years ago

    一般要用全仓吧。

    5 years ago

    杠杆可以在交易所具体设置,根据自身风险偏好。

    5 years ago

    既然开的是合约,为啥没有合约倍数的设定呢?买卖都是多少倍的呢

    5 years ago

    谢谢梦大,我终于能从头到尾看懂了,
    然后学会了挂单监控了,然后写了一个双边的马丁。两天时间,写了580行。。。。。
    谢谢梦大[抱拳]

    5 years ago

    云总 666!

    5 years ago

    img
    false true 交换下?

    5 years ago

    那这个变量名叫 isFindBuyId 就不合适了吧。 应该叫isNotFindBuyId了。

    5 years ago

    如果

    5 years ago

    所有者权益合计

    5 years ago

    需要止损吗

    5 years ago

    这策略没设计止损。。所以跑出来的曲线可以看到是一路往上的。

    5 years ago

    马丁,回测下了,归0

    5 years ago

    哈哈,马丁的归宿。
    本篇主要是教学策略设计,不用太在意收益。

    5 years ago

    开单数量那里没看懂呢= =,那个n永远都等于1

    5 years ago

    那个N是为了做之后的改动用的,比如想n倍距离加仓,暂时可以定1。

    5 years ago

    策略是多空双开吗?还是单开的

    5 years ago

    单开的。

    5 years ago
  • 1
iPhone Download
Forums
PINE Language
© 2015 - ∞ INVENTOR PTE LTD (SG)