2
フォロー
20
フォロワー

通貨ベースの空売り手数料裁定戦略の定量的実装

作成日:: 2025-01-21 17:06:52, 更新日:: 2025-02-17 11:25:01
comments   0
hits   455

通貨ベースの空売り手数料裁定戦略の定量的実装

暗号通貨市場の激しい変動の中でも安定を保ち、強気相場や弱気相場に関係なく持続的にプラスの収益をもたらす戦略があると想像してみてください。まるでファンタジーのようですね?実はそうではありません。手数料の1倍で通貨を空売りする裁定取引戦略は、何もせずにお金を稼ぐ魔法のツールです。

この戦略は、通貨ベースの契約と資金調達率のメカニズムの独自の特性を巧みに活用することで、強気市場で安定した収益を得られるだけでなく、弱気市場でのリスクを効果的に回避し、市場サイクル全体で安定した収益を達成することができます。コインベースの契約の「現金保護」の性質により、市場価格が大幅に変動した場合でも、戦略の合計価値が安定したままになります。資金調達率は、永久契約の中心的なメカニズムとして、戦略に追加の収入源を提供します。この記事では、コインベースの空売り戦略の核心ロジック、実装プロセス、長所と短所を深く分析し、投資家がデジタル通貨市場でこの戦略を通じて「受動的収入」を達成する方法を理解できるようにします。定量取引の初心者であっても、経験豊富な投資家であっても、この戦略は深く理解して試してみる価値があります。

コインベースの空売り

通貨基準の特徴

コイン証拠金契約の単位はシートで測定され、各シートの価値は固定されています(たとえば、BTC の 1 契約は 100 USD、ETH は 10 USD の価値があります)。この特徴は、レバレッジ1倍の場合、市場価格が大きく変動しても、理論的には追証が発生しないことを意味します。

損益分析

現在の価格が 100 USD であると仮定すると、10 のコイン マージン ショート契約が開かれ、その価値は 100 USD に等しく、1 コイン単位に変換されます。

  1. 価格引き下げ

    • 価格が 50 ドルに下がると、収益率は次のようになります。 [ \text{収益率} = \frac{100 - 50}{50} = 100% ] 保有するコインの数は 2 になり、合計値は次のようになります。 [ 2 \times 50 = 100 , \text{USD} ]
  2. 価格上昇

    • 価格が 200 ドルに上昇すると、収益率は次のようになります。 [ \text{収益率} = \frac{100 - 200}{200} = -50% ] 保有コインの枚数は 0.5 になり、合計値はそのままです。 [ 0.5 \times 200 = 100 , \text{USD} ]

したがって、ある程度、通貨ベースの空売りの合計値は安定しており、これは現金保全操作です。では、この戦略の利益はどこから来るのでしょうか? 次の概念を紹介しましょう。資金調達率

資金調達率

通貨ベースの空売り戦略では、資金調達率これは戦略リターンの中核的な推進要因の 1 つであり、その特性と変化は戦略の安定性と収益性に直接影響します。資金調達率の特性を適切に活用することで、戦略はさまざまな市場環境で良好なパフォーマンスを維持できますが、潜在的な限界にも注意する必要があります。

資金調達率の定義と特徴

資金調達率は、永久契約市場における規制メカニズムであり、ロング側とショート側の保有コストのバランスを取り、永久契約価格がスポット価格から長期間逸脱するのを防ぐことを目的としています。実際、CFA を勉強した友人は、永久契約の元の名前であるスワップを今でも覚えているでしょう。永久契約の資金調達率メカニズムの設計上のヒントは、主に伝統的な金融における金利スワップから得られています。金利スワップでは、2 つの当事者が合意された金利 (固定金利と変動金利など) に基づいて定期的に金利の支払いを交換し、金利変動のリスクをヘッジします。同様に、永久契約の資金調達率メカニズムも、定期的に手数料を支払ったり徴収したりすることでロング側とショート側の保有コストのバランスを取り、契約価格とスポット価格の差が大きくなりすぎないようにします。

通貨ベースの空売り手数料裁定戦略の定量的実装

資金調達率の導入は、本質的には永久契約とスポット価格の間の基準問題を解決することです。永久契約価格がスポット価格よりも高い場合、資金調達率はプラスとなり、ロングはショートに対して手数料を支払います。永久契約価格がスポット価格よりも低い場合、資金調達率はマイナスとなり、ショートはロングに対して手数料を支払います。このメカニズムは、金利スワップの中核概念を活用するだけでなく、デジタル通貨市場の特性も組み合わせて、独自の市場規制ツールを形成します。デジタル通貨の分野では、その主な特徴は次のとおりです。

  1. 市場の需要と供給は:資金調達率は、市場におけるロングとショートの需給関係によって決定され、ロングとショートの勢力間のゲームの結果です。
  2. 定期支払い:資金調達率は一定期間(8時間など)ごとに支払われ、ロングポジションとショートポジションの間で手数料が移動されます。
  3. 感情的な反省:資金調達率がプラスの場合、通常、市場センチメントが強気で、永久契約価格がスポット価格よりも高いことを示し、資金調達率がマイナスの場合、通常、市場センチメントが弱気で、永久契約価格がスポット価格よりも低いことを示します。

正の資金調達率(資金調達率 > 0)

  • パフォーマンス: 資金調達率がプラスの環境では、ロングはショートに対して手数料を支払う必要があります。
  • 収益ロジック:資金調達率が安定的に支払われるため、ショートポジションを保有することで資金調達手数料を継続的に徴収する戦略であり、市場価格が上昇してもリターンに大きなマイナスの影響を与えることはありません。たとえば、資金調達率が 0.02%/8 時間の場合、10,000 ドル相当の契約を保有すると、1 日あたりの収益は次のようになります。 [ 1 日の収益 = 10,000 \times 0.02% \times 3 = 6 , \text{USDT} ] この収入源は比較的安定しており、価格変動との相関性が低くなります。

マイナスの資金調達率(資金調達率 < 0)

  • パフォーマンス:資金調達率がマイナスの場合、ショートポジションはロングポジションに手数料を支払う必要があり、戦略のリターンが圧縮されたり、損失が発生する可能性があります。
  • リスクポイント:長期にわたる弱気相場など、マイナスの資金調達金利が長期間継続したり、大きく変動したりする場合には、資金調達手数料の支払いによりコストが増加し、全体的な収益が運用コストをカバーできなくなる可能性があります。

戦略的な利益源

ジナン師がおっしゃったように、戦略構築の初期段階では、戦略のリターンとリスクの源泉を理解する必要があります。以上を踏まえると、通貨基準での空売り総額は安定的に推移し、収益源は資金調達金利の裁定取引となることがわかります。学生の中には、資金調達率が今後も安定したプラスの収益をもたらし続けるのか疑問に思う人もいるかもしれません。 DATADATA国際ステーションでは、データ分析業務を行っています。

SELECT 
    Exchange,
    Symbol,
    toDateTime(Time / 1000) AS Time,  -- 将毫秒时间戳转换为时间戳
    Rate,
    SUM(Rate) OVER (PARTITION BY Exchange, Symbol ORDER BY Time) AS CumulativeRate  -- 计算累加的 Rate
FROM 
    klines.funding
WHERE 
    Exchange = '{{exchange}}' 
    AND Symbol = '{{symbol}}'
ORDER BY 
    Time;

動的パラメータは Binance 取引所を使用し、契約はビットコイン標準 (btc_usd) 契約を選択して累積資金調達率を表示します。 2020年から現在に至るまで、資金調達率収入は着実に増加しており、5年間の累計収入は50%に達していることがわかります。数百や数千の利益とは比較できませんが、比較的安定しているので、この戦略の利益源を整理することができます。

コインベースの空売り戦略では、資金調達率が利益の重要な源泉となります。コイン証拠金契約の単位は固定されているため、市場価格が変動しても、空売り業者の契約価値の変化は通常は制御可能であり、資金調達率が戦略の主な利益源となります。資金調達率が戦略に与える具体的な影響は次のとおりです。

  1. 強気相場フェーズ(資金調達率はプラス)

    • 市場現象強気相場では、市場心理が高まっているため、投資家は一般的にロングポジションを取る傾向があり、その結果、ロングポジションが増加し、資金調達率がプラスの値に押し上げられます。
    • 収益ロジックこの場合、空売り業者はロングが支払う資金調達率から利益を得ることになり、それがこの戦略の主な利益源となります。資金調達率がプラスであるため、ショートポジションで利益を上げ続けることができ、得られた資金調達率を活用することで、ショートポジションを継続的にオープンし、より多くの資金調達率のメリットを得ることができます。
    • 具体的な影響: 資金調達率がプラスで安定している場合、ショートは定期的に資金調達率を受け取り、価格変動による影響をあまり受けません。市場価格が上昇したとしても、空売り業者は契約で大きな見かけ上の損失に直面する可能性がありますが、全体として、資金の純価値は比較的安定しています。これは、この戦略の利益源が価格変動ではなく、主に資金調達率の収集に依存しているためです。価格変動は契約の見かけ上の損失に影響を及ぼす可能性がありますが、ショートポジションの契約価値の変化は制御可能であるため、ファンドの主な利益は市場価格の変動ではなく、資金調達レートの定期的な収集から得られます。これにより、価格変動のリスクをある程度相殺し、資金の安定した増加を維持する戦略が可能になります。
  2. 弱気相場局面(マイナスの資金調達率)

    • 市場現象弱気相場では、市場価格が急落し、ショートポジションが急増するため、資金調達率がマイナスになり、ショートポジションを持つ人がロングポジションを持つ人に支払う必要が生じます。しかし、近年のデジタル通貨市場の活況により、弱気相場の局面は比較的稀です。
    • 収益ロジック: 資金調達率はマイナスであり、ショートは手数料を支払う必要がありますが、ショート契約の単位は固定されており、ショートポジションの契約価値はほとんど変わらないため、戦略のヘッジ特性は依然として有効です。激しい価格変動によって大きな損失が発生することはありません。同時に、資金調達率の負担は比較的制御可能であり、戦略はある程度安定したままになります。

これら 2 つの市場環境を分析すると、通貨ベースの空売り戦略の収益性とリスクは主に資金調達率によって影響を受けることがわかります。強気相場で資金調達率がプラスの場合、空売り業者はそこから利益を得ることができます。一方、弱気相場では、資金調達率がマイナスであっても、契約価値の変化は制御可能であるため、この戦略は依然として価値を維持する強力な能力を備えています。

ポリシーロジックアーキテクチャ

堅牢な戦略フレームワークは、戦略を成功裏に実行するための鍵です。戦略がさまざまな市場状況下で安定的に機能し、リスクやボラティリティに効果的に対処できるように、明確な実行フレームワークを提供します。ここでは、小大神の U ベースのマルチ通貨契約戦略フレームワークを参照し、通貨標準に一定の修正と改善を加えます。

'''backtest
start: 2024-11-20 00:00:00
end: 2024-11-20 01:00:00
period: 1d
basePeriod: 1m
exchanges: [{"eid":"Futures_OKX","currency":"BTC_USD"}]
'''

import time
import json 

# 全局变量,储存数据
SYMBOLS = 'BTC'     # SYMBOLS代表要交易的币种,格式如"BTC,ETH,LTC"
QUOTO = 'USD'       # QUOTO为基础货币, 币本位为USD
INTERVAL = 5        # INTERVAL代表循环的间隔
ICEMONEY = 2000     # 冰山下单金额
ROLLINGNUM = 1      # 滚动盈利加仓数量


Info = {
    'trade_symbols': SYMBOLS.split(','),  # 交易币种
    'base_coin': QUOTO,                   # 基础货币
    'ticker': {},                         # 行情数据
    'order': {},                          # 订单信息
    'account': {},                        # 账户信息
    'precision': {},                      # 精度信息
    'position': {},                       # 仓位信息
    'time': {},                           # 时间相关数据
    'count': {},                          # 计数器
    'interval': INTERVAL                  # 循环的间隔时间
}

# 初始化策略
def InitInfo():

    # 初始化时间数据,控制更新的时间
    Info['time'] = {
        'update_ticker_time': 0,    # 更新行情的时间
        'update_pos_time': 0,       # 更新仓位的时间
        'update_profit_time': 0,    # 更新利润的时间
        'update_account_time': 0,   # 更新账户信息的时间
        'update_status_time': 0,    # 更新状态的时间
        'last_loop_time': 0,        # 上一次主循环的时间
        'loop_delay': 0,            # 循环延迟
        'start_time': time.time()   # 起始时间
    }

    # 初始化每个交易币种的数据
    for symbol in Info['trade_symbols']:

        Info['account'][symbol] = {
            'init_balance': 0,  # 初始余额
            'margin_balance': 0,  # 保证金余额
            'margin_used': 0,  # 已用保证金
            'margin_free': 0,  # 可用保证金
            'profit': 0,  # 总收益
            'profit_rate': 0,  # 收益率
            'unrealised_profit': 0,  # 未实现收益
        } # 初始化账户信息,初始余额为0

        Info['ticker'][symbol] = {'last': 0, 'ask': 0, 'bid': 0}  # 行情
        Info['order'][symbol] = {                                 # 订单信息
            'buy': {'id': 0, 'price': 0, 'amount': 0},
            'sell': {'id': 0, 'price': 0, 'amount': 0}
        }
        Info['position'][symbol] = {                              # 仓位信息
            'amount': 0, 'hold_price': 0, 'unrealised_profit': 0, 'open_time': 0, 'value': 0
        }
        Info['precision'][symbol] = {}  # 精度信息初始化为空
        Info['position'][symbol] = {                              # 仓位信息
            'amount': 0, 'hold_price': 0, 'unrealised_profit': 0, 'open_time': 0, 'value': 0
        }

# 获取精度信息
def GetPrecision():
    # 获取交易所的市场信息

    # 回测系统需要获取行情信息后, 才能获取市场信息,实盘系统可忽略
    for symbol in Info['trade_symbols']:
         curcontract = symbol + '_' + QUOTO + '.swap'
         exchange.GetTicker(curcontract) 
        
    exchange_info = exchange.GetMarkets()
    
    # 遍历市场中的所有交易对
    for pair, data in exchange_info.items():
        symbol = pair.split('_')[0]  # 永续合约交易对的格式为 BTC_USDT.swap
        
        # 检查该交易对是否为我们要交易的币种,基础货币是否匹配,且是永续合约
        if symbol in Info['trade_symbols'] and pair.split('.')[0].endswith(Info['base_coin']) and pair.endswith('swap'):
            # 获取该交易对的精度信息
            Info['precision'][symbol] = {
                'tick_size': data['TickSize'],                  # 价格精度
                'amount_size': data['AmountSize'],              # 数量精度
                'price_precision': data['PricePrecision'],      # 价格小数位精度
                'amount_precision': data['AmountPrecision'],    # 数量小数位精度
                'min_qty': data['MinQty'],                      # 最小下单数量
                'max_qty': data['MaxQty'],                      # 最大下单数量
                'min_notional': data['MinNotional'],            # 最小交易额
                'ctVal': data['CtVal']                          # 合约价值,如1张代表100USD
            }

            Log(f"初始化币种信息: {symbol}, "
                 f"价格精度: {Info['precision'][symbol]['tick_size']}, "
                 f"数量精度: {Info['precision'][symbol]['amount_size']}, "
                 f"价格小数位精度: {Info['precision'][symbol]['price_precision']}, "
                 f"数量小数位精度: {Info['precision'][symbol]['amount_precision']}, "
                 f"最小下单数量: {Info['precision'][symbol]['min_qty']}, "
                 f"最大下单数量: {Info['precision'][symbol]['max_qty']}, "
                 f"最小交易额: {Info['precision'][symbol]['min_notional']}, "
                 f"合约价值(张): {Info['precision'][symbol]['ctVal']}")


# 更新行情信息
def UpdateTicker():
    
    # 记录当前更新时间戳
    Info['time']['update_ticker_time'] = time.time() * 1000 # 使用time.time()获取当前时间的时间戳
    
    # 遍历获取到的行情数据
    for symbol in Info['trade_symbols']:
        
        curcontract = symbol + '_' + QUOTO + '.swap'
        data = exchange.GetTicker(curcontract)
        
        if not data:
            Log("获取行情失败", GetLastError())
            return
        
        # 更新行情的卖出价、买入价和最后成交价
        Info['ticker'][symbol]['ask'] = float(data['Sell'])  # 卖出价
        Info['ticker'][symbol]['bid'] = float(data['Buy'])   # 买入价
        Info['ticker'][symbol]['last'] = float(data['Last']) # 最后成交价


# 更新账户信息
def UpdateAccount():
    # 遍历所有交易币种,更新账户信息
    for symbol in Info['trade_symbols']:    
        curcontract = symbol + '_' + QUOTO  # 拼接币种和报价货币,形成合约标识
        exchange.SetCurrency(curcontract)  # 设置当前合约
        
        # 获取账户信息
        account = exchange.GetAccount()
        
        # 如果账户信息获取失败,记录日志并结束函数
        if account is None:
            Log(curcontract, ": 更新账户失败")
            return
        
        # 计算账户的关键信息
        # 'Stocks': 可用余额, 'FrozenStocks': 冻结余额, 'Equity': 总权益, 'UPnL': 未实现盈亏, 区别U本位(Balance)
        Info['account'][symbol]['margin_used'] = account['Equity'] - account['Stocks']  # 已用保证金
        Info['account'][symbol]['margin_balance'] = account['Equity']  # 当前账户总权益
        Info['account'][symbol]['margin_free'] = account['Stocks']  # 当前可用余额
        Info['account'][symbol]['unrealised_profit'] = account['UPnL']  # 未实现盈亏

        # 从全局存储中读取账户初始余额字典
        accDict = _G("init_balance")
        if accDict is None:
            accDict = {}  # 如果全局存储为空,则初始化为空字典

        # 初始化账户初始余额(仅在第一次运行时设置)
        if not Info['account'][symbol]['init_balance']:
            # 如果全局存储有记录且余额大于0,则使用该记录作为初始余额
            if accDict and accDict.get(symbol) and accDict[symbol] > 0:
                Info['account'][symbol]['init_balance'] = round(accDict[symbol], 2)
            else:
                # 否则,将当前保证金余额作为初始余额
                Info['account'][symbol]['init_balance'] = Info['account'][symbol]['margin_balance'] * Info['ticker'][symbol]['last']
                accDict[symbol] = Info['account'][symbol]['init_balance']  # 更新全局存储
                _G("init_balance", accDict)

        # 计算账户利润及利润率
        Info['account'][symbol]['profit'] = round(Info['account'][symbol]['margin_balance'] * Info['ticker'][symbol]['last'] - Info['account'][symbol]['init_balance'], 2)  # 当前利润
        Info['account'][symbol]['profit_rate'] = round((100 * Info['account'][symbol]['profit']) / Info['account'][symbol]['init_balance'], 2)  # 当前利润率(百分比)

# 更新仓位信息
def UpdatePosition():
    
    # 获取永续合约的仓位信息
    # 调用接口获取指定币种的仓位信息
    pos = exchange.GetPositions(Info['base_coin'] + ".swap")
    
    # 记录仓位信息的更新时间(单位:毫秒)
    Info['time']['update_pos_time'] = time.time() * 1000

    # 初始化仓位信息
    # 为每个交易币种创建默认的仓位信息
    position_info = {symbol: {'amount': 0, 'hold_price': 0, 'unrealised_profit': 0} for symbol in Info['trade_symbols']}

    # 遍历获取到的仓位信息,更新对应币种的仓位数据
    for data in pos:
        # 提取币种名称(Symbol)的一部分作为标识
        symbol = data['Symbol'].split("_")[0]
        
        # 过滤掉不属于指定基准币种或不在交易列表中的币种
        if not data['Symbol'].split(".")[0].endswith(Info['base_coin']) or symbol not in Info['trade_symbols']:
            continue
        
        # 更新仓位信息,区分多头和空头(通过 Type 字段)
        position_info[symbol] = {
            'amount': data['Amount'] if data['Type'] == 0 else -data['Amount'],  # 多头为正,空头为负
            'hold_price': data['Price'],  # 仓位持有价格
            'unrealised_profit': data['Profit']  # 未实现盈亏
        }

    # 初始化每个币种的仓位统计数据
    # long: 多头价值, short: 空头价值, total: 总仓位价值, leverage: 杠杆率
    for symbol in Info['trade_symbols']:
        Info['count'][symbol] = {'long': 0, 'short': 0, 'total': 0, 'leverage': 0}

    # 遍历更新后的仓位信息
    for symbol, info in position_info.items():
        # 计算仓位变化量
        deal_volume = abs(info['amount'] - Info['position'][symbol]['amount'])
        # 计算变化方向(正数为增仓,负数为减仓)
        direction = 1 if info['amount'] - Info['position'][symbol]['amount'] > 0 else -1
        
        # 如果仓位发生变化,记录成交信息
        if deal_volume:
            # 获取成交价格(买入或卖出)
            deal_price = Info['order'][symbol]['buy']['price'] if direction == 1 else Info['order'][symbol]['sell']['price']
            # 打印仓位更新日志
            Log(
                symbol,
                "仓位更新:",
                round(Info['position'][symbol]['amount'], 1),
                " -> ",
                round(info['amount'], 1),
                ", 买" if direction == 1 else ", 卖",
                ", 成交价:",
                deal_price,
                ", 成本价:",
                round(Info['position'][symbol]['hold_price'], Info['precision'][symbol]['price_precision']),
            )

        # 更新仓位信息
        Info['position'][symbol]['amount'] = info['amount']  # 更新仓位数量
        Info['position'][symbol]['hold_price'] = info['hold_price']  # 更新持仓价格
        Info['position'][symbol]['value'] = round(Info['position'][symbol]['amount'] * Info['precision'][symbol]['ctVal'], 2)  # 仓位价值
        Info['position'][symbol]['unrealised_profit'] = info['unrealised_profit']  # 更新未实现盈亏

        # 统计多头和空头仓位价值
        if Info['position'][symbol]['amount'] > 0:
            # 如果为多头,增加多头仓位价值
            Info['count'][symbol]['long'] += abs(Info['position'][symbol]['value'])
        else:
            # 如果为空头,增加空头仓位价值
            Info['count'][symbol]['short'] += abs(Info['position'][symbol]['value'])

        # 计算仓位总价值(按最新价格计算)
        Info['count'][symbol]['total'] = round((Info['count'][symbol]['long'] + Info['count'][symbol]['short']) / Info['ticker'][symbol]['last'], 2)
        # 计算杠杆率(总仓位价值与账户保证金的比值)
        Info['count'][symbol]['leverage'] = round(Info['count'][symbol]['total'] / Info['account'][symbol]['margin_balance'], 2)

# 订单函数
def Order(symbol, direction, price, amount, msg):
    pair = f"{symbol}_{Info['base_coin']}.swap"  # 构造交易对名称
    ret = exchange.CreateOrder(pair, direction, price, amount, msg)  # 执行下单操作
    
    # 判断是否下单成功
    if ret:
        Info['order'][symbol][direction]['id'] = ret  # 记录订单ID
        Info['order'][symbol][direction]['price'] = price  # 记录下单价格
        Log('记录下单价格:', price, direction, Info['order'][symbol][direction]['price'], )
    else:
        Log(f"{symbol} {direction} {price} {amount} 下单异常")  # 输出异常信息

# 交易函数
def Trade(symbol, direction, price, amount, msg):
    
    # 根据最小价格变动调整价格
    price = round(price - (price % Info['precision'][symbol]['tick_size']), Info['precision'][symbol]['price_precision'])
    
    # 计算调整后的交易数量
    amount = amount / Info['precision'][symbol]['ctVal']  # 计算真实合约数量
    amount = round(amount - (amount % Info['precision'][symbol]['amount_size']), Info['precision'][symbol]['amount_precision'])

    # 限制最大交易数量
    if Info['precision'][symbol]['max_qty'] > 0:
        amount = min(amount, Info['precision'][symbol]['max_qty'])
    
    new_order = False
    
    # 如果新价格与之前的订单价格差异大于0.0001,则重新下单

    if Info['order'][symbol][direction]['price'] > 0 and abs(price - Info['order'][symbol][direction]['price']) / price > 0.0001:
        Log('已持订单,订单价格发生变化')
        new_order = True
    
    # 如果交易数量为0或者当前订单ID为0,则撤单
    if amount <= 0 or Info['order'][symbol][direction]['id'] == 0:
        Log('新订单产生')
        new_order = True
    
    # 如果需要新订单
    if new_order:
        # 如果有原有订单,撤销它
        if Info['order'][symbol][direction]['id'] != 0:
            exchange.CancelOrder(Info['order'][symbol][direction]['id'])
            Info['order'][symbol][direction]['id'] = 0
            Info['order'][symbol][direction]['price'] = 0
            Log('撤单成功:', symbol)
        
        
        # 如果更新仓位或ticker的延迟太高,则不下单
        #if (time.time() * 1000 - Info['time']['update_pos_time'] > 2 * Info['interval'] * 1000 or 
        #    time.time() * 1000 - Info['time']['update_ticker_time'] > 2 * Info['interval'] * 1000):
        #    Log('仓位更新时间', time.time() * 1000, Info['time']['update_pos_time'], time.time() * 1000 - Info['time']['update_pos_time'])
        #    Log('Ticker更新时间', time.time() * 1000, Info['time']['update_ticker_time'], time.time() * 1000 - Info['time']['update_ticker_time'])
        #    Log('延迟过高')
        #    return
        
        # 如果订单金额或数量过低,不执行下单操作
        if price * amount <= Info['precision'][symbol]['min_notional'] or amount < Info['precision'][symbol]['min_qty']:
            Log(f"{symbol} 下单量太低", price * amount)
            return
        
        # 执行下单操作
        Log('order下单:', symbol)
        Order(symbol, direction, price, amount, msg)


# 更新状态函数
def UpdateStatus():
    
    # 更新状态时间
    Info['time']['update_status_time'] = time.time() * 1000

    # 账户信息表格
    table1 = {
        "type": "table",
        "title": "账户信息",
        "cols": [
            "币种", "初始权益", "实时权益", "可用余额", 
            "总收益", "收益率"
        ],
        "rows": [],
    }

    # 遍历每个交易对,填充交易对信息
    for symbol in Info['trade_symbols']:
        table1['rows'].append([
            symbol,  # 币种
            round(Info['account'][symbol]['init_balance'], 2),  # 初始权益
            round(Info['account'][symbol]['margin_balance'] *  Info['ticker'][symbol]['last'], 2),  # 实时权益
            round(Info['account'][symbol]['margin_free'] *  Info['ticker'][symbol]['last'], 2), # 可用余额
            round(Info['account'][symbol]['profit'], 2),  # 总收益
            str(Info['account'][symbol]['profit_rate']) + "%"  # 收益率
        ])

    # 交易对信息表格
    table2 = {
        "type": "table",
        "title": "交易对信息",
        "cols": [
            "币种", "方向", "数量", "持仓价格", "持仓价值", 
            "现价"
        ],
        "rows": [],
    }

    # 遍历每个交易对,填充交易对信息
    for symbol in Info['trade_symbols']:
        table2['rows'].append([
            symbol,  # 币种
            "LONG" if Info['position'][symbol]['amount'] > 0 else "SHORT",  # 方向
            Info['position'][symbol]['amount'],  # 数量
            round(Info['position'][symbol]['hold_price'], Info['precision'][symbol]['price_precision']),  # 持仓价格
            round(Info['position'][symbol]['value'], 2),  # 持仓价值
            round(Info['ticker'][symbol]['last'], Info['precision'][symbol]['price_precision'])  # 现价
        ])

    # 输出状态日志
    LogStatus(
        f"初始化时间: {time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(Info['time']['start_time']))}\n",
        f"`{json.dumps(table1)}`\n" + f"`{json.dumps(table2)}`\n",
        f"循环延时: {str(Info['time']['loop_delay']) + 'ms'}\n",
        f"最后执行时间: {_D()}\n"
    )

    totalprofit = 0
    for symbol in Info['trade_symbols']:
        totalprofit += Info['account'][symbol]['profit']  

    # 每10秒钟更新一次账户信息
    if time.time() * 1000 - Info['time']['update_profit_time'] > 10 * 1000:
        LogProfit(round(totalprofit, 3), '&')  # 输出收益日志
        Info['time']['update_profit_time'] = time.time() * 1000  # 更新收益时间


def MakeOrder():
    
    # 遍历所有交易对
    for symbol in Info['trade_symbols']:
        
        availBal = Info['account'][symbol]['margin_free'] *  Info['ticker'][symbol]['last'] #可用金额
        sell_price = Info['ticker'][symbol]['ask'] #卖出价格

        if availBal > ICEMONEY: #可用金额大于冰山挂单数量,起始建仓
            Trade(symbol, "sell", sell_price, ICEMONEY, symbol)  # 执行买入操作
        elif availBal > ROLLINGNUM * Info['precision'][symbol]['ctVal']: #可用盈利大于滚动加仓数量,逐步下单
            Trade(symbol, "sell", sell_price, ROLLINGNUM * Info['precision'][symbol]['ctVal'], symbol)  # 执行买入操作

def OnTick():
         
    # 更新市场行情信息
    UpdateTicker()

    # 更新账户信息
    UpdateAccount()
     
    # 更新持仓信息
    UpdatePosition()

    # 执行下单操作
    MakeOrder()
    
    # 更新状态信息
    UpdateStatus()

def main():

    LogReset(0)                # 日志重置
    Log('策略起始#0000ff')
    # 初始化信息
    InitInfo()                 # 初始化币种信息
    GetPrecision()             # 获取精度信息
    exchange.SetMarginLevel(1) # 设置杠杆倍数
    
    while True:  # 无限循环
        
        loop_start_time = time.time() * 1000  # 获取当前时间(毫秒)
        
        # 检查上次循环时间与设定的间隔时间是否已过
        if time.time() * 1000 - Info['time']['last_loop_time'] > Info['interval'] * 1000:
            
            OnTick()  # 调用 OnTick 函数

            # 更新最后一次循环时间
            Info['time']['last_loop_time'] = time.time() * 1000
            # 计算当前循环的延迟时间
            Info['time']['loop_delay'] = time.time() * 1000 - loop_start_time
        
        # 暂停5毫秒,避免过度消耗CPU资源
        Sleep(5)

1. グローバル変数と関数の説明

この戦略は単純な変数定義に基づいており、モジュラー関数を通じてローリングポジションの追加とステータス監視を実装します。

  • SYMBOLS: 取引通貨(「BTC」など)。
  • QUOTO:基本通貨、通貨基準は通常USDです。
  • INTERVAL: ポリシーサイクル間の時間間隔。
  • ICEMONEY: アイスバーグ注文に使用される初期注文金額。
  • ROLLINGNUM: 利益確定後に追加されたポジション数。

2. コア機能モジュール

各機能モジュールの簡単な説明は次のとおりです。

  1. 初期化関数 (InitInfo)
    取引通貨情報と初期アカウントステータスを読み込むために使用されます。

  2. 精度情報を取得する (GetPrecision)
    取引所 API を通じて、各取引ペアの最小注文サイズと契約値を取得します。

  3. アップデートティッカー
    最良入札価格、最良売り価格、最新価格など、現在の市場情報を定期的に入手します。

  4. アカウントとポジションの更新 (UpdateAccount、UpdatePosition)
    口座残高とポジション情報のリアルタイム同期は、取引決定の基礎となります。

  5. 取引と注文管理(注文、取引)
    指値注文と成行注文をサポートする、統合された注文配置および実行機能。

  6. ステータス監視 (UpdateStatus)
    現在の損益や未約定の注文など、戦略のステータスを追跡します。

3. 戦略注文ロジック(MakeOrder)

戦略の核心は初期位置(氷山の位置)とローリングポジション(ローリング位置パラメータ ROLLINGNUM によって制御されます)。具体的なロジックの詳細な説明は次のとおりです。

  1. 初期位置チェック:口座残高が初期氷山開設額(ICEMONEY)より大きいか確認します。条件が満たされた場合、一度にポジションを開くことによる過度の価格スリッページを軽減するために、ポジションは段階的にバッチで開かれます。
  2. ローリングポジション戦略:口座の収益性(資金調達率収入)に応じて、ポジションを合理的に増加し、ポジションのローリング増加を通じて収入を最適化し、戦略全体の収益性を向上させます。

通貨ベースの空売り手数料裁定戦略の定量的実装

戦略のバックテスト結果によると、この戦略は複数の市場サイクル、特に資金調達率が長期にわたってプラスであった強気市場で安定した収益を達成していることがわかります。したがって、この戦略は、ある程度大規模な資金管理に非常に適しています。低いボラティリティと安定した収益という特性により、リスク管理と安定した収益という大規模ファンドの二重のニーズを満たすことができます。同時に、この戦略では 1 倍のレバレッジを採用しており、高いレバレッジによる清算のリスクを回避し、さらに安全性を高めています。

戦略の長所と短所の分析

アドバンテージ

  1. 戦略はシンプルで実行しやすい
    ロジックが明確で複雑な計算を必要としないため、ヘッジファンドや個人投資家による大規模な資金運用に適しています。

  2. 強いリスク耐性
    1 倍のレバレッジにより清算のリスクを回避でき、通貨ベースの特性により、市場の大きな変動に関係なく米ドルの価値が一定に保たれます。

  3. 安定した収入
    強気相場では、資金調達率が高く、スケーラビリティが強くなり、結果として得られる通貨は他の投資(ステーキングなど)に使用できます。

欠点

  1. 通貨と市場の状況への強い依存
    これは欠陥です。BNB 契約など、通貨の資金調達率が長期間プラスの場合 (ショートがロングを支払う)、DATADATA を使用して BNB コインベースの契約を選択します。取引所の設定により、資金調達率がマイナスの値に蓄積されることがわかります。また、大きなサイクルが長期弱気相場(2022年)にあり、資金調達率がマイナスの場合、リターンが戦略運用のコストをカバーできない可能性があります。

  1. 戦略の厳格さの欠如
    現在の戦略には、強気相場と弱気相場を切り替える際の対応策(ストップロスやテイクプロフィット戦略など)の欠如などの動的調整ロジックが含まれていません。

  2. 利益率が限られている
    手数料を「定額」で請求することに適しており、市場の大きな変動時に超過収益を獲得することができません。場合によっては、収益率は従来の債券ファンドほど良くありません。

締めくくり

コインベースのワンタイム空売り手数料裁定戦略は、コインベースの契約の特殊性を最大限に活用し、資本保全と安定した価値上昇のための低リスクソリューションを提供します。しかし、市場のさまざまな段階に応じて、資金調達率や潜在的なリスクの変動に対応するために、戦略にはある程度の柔軟性が必要です。将来の最適化の方向性としては、次のようなものが考えられます。

  1. 強気相場と弱気相場を切り替えるための動的な管理手段を追加します。
  2. 資金調達率の変化に応じてポジション追加のペースを調整します。

しかし本質的には、この戦略には矛盾。この戦略の当初の前提は、デジタル通貨市場は長期的に強気相場にあり、通貨ベースの契約をショートすることで安定したキャッシュフローを維持し、資金調達率のメリットを得ることができるというものです。しかし、市場が長期的な強気相場にあると仮定すると、コインを蓄えて(hlod)、ビットコインの着実な上昇を待つという選択をするのはなぜではないでしょうか?もちろん、安定した収益を追求する人にとっては、この戦略は依然として信頼できます。この記事の目的は、この設計アイデアを紹介し、それをさらに改善し最適化できる定量的な投資戦略フレームワークを提供することです。この戦略がデジタル通貨の定量投資家にとって効果的なツールとなることが期待されます。

参考文献

FMZ アップグレード後にユニバーサルなマルチ通貨取引戦略を迅速に構築する方法

アルゴリズムトレード実践日記(19) - 裁定戦略詳細解説シリーズ(1):通貨ベースの空売り手数料裁定

親切なヒント: 投資にはリスクが伴いますので、市場に参入する際には注意してください。投資家は、自身のリスク許容度に応じて、戦略ロジックとリスクを十分に理解した上で、資金を合理的に配分し、ポジションとレバレッジを厳密に管理することをお勧めします。この記事の内容は参考目的のみであり、いかなる投資アドバイスも構成するものではありません。