2
Suivre
20
Abonnés

Mise en œuvre quantitative d'une stratégie d'arbitrage des frais de vente à découvert basée sur les devises

Créé le: 2025-01-21 17:06:52, Mis à jour le: 2025-02-17 11:25:01
comments   0
hits   452

Mise en œuvre quantitative d’une stratégie d’arbitrage des frais de vente à découvert basée sur les devises

Imaginez avoir une stratégie capable de rester stable au milieu des fluctuations sauvages du marché des crypto-monnaies et qui peut vous apporter des rendements positifs durables, quels que soient les marchés haussiers ou baissiers. Cela ressemble à un fantasme ? En fait, ce n’est pas le cas. La stratégie d’arbitrage consistant à vendre à découvert la devise avec des frais uniques est un outil magique pour gagner de l’argent sans rien faire.

En utilisant intelligemment les propriétés uniques des contrats basés sur les devises et le mécanisme du taux de financement, cette stratégie peut non seulement obtenir des rendements stables dans un marché haussier, mais également éviter efficacement les risques dans un marché baissier et obtenir des rendements stables à travers les cycles de marché. La nature « protégée par des liquidités » des contrats basés sur des pièces de monnaie garantit que la valeur totale de la stratégie reste stable même si les prix du marché fluctuent considérablement. Le taux de financement, en tant que mécanisme de base des contrats perpétuels, fournit une source de revenus supplémentaire pour la stratégie. Cet article analysera en profondeur la logique de base, le processus de mise en œuvre, les avantages et les inconvénients de la stratégie de vente à découvert basée sur les pièces de monnaie pour aider les investisseurs à comprendre comment obtenir un « revenu passif » grâce à cette stratégie sur le marché des devises numériques. Que vous soyez un novice en trading quantitatif ou un investisseur expérimenté, cette stratégie mérite d’être comprise et essayée en profondeur.

Vente à découvert basée sur des pièces de monnaie

Caractéristiques de l’étalon monétaire

L’unité du contrat à marge de pièces est mesurée en feuilles, et la valeur de chaque feuille est fixe (par exemple, 1 contrat de BTC vaut 100 USD et 10 USD d’ETH). Cette fonctionnalité signifie que dans le cas d’un effet de levier de 1x, même si le prix du marché fluctue fortement, il n’y aura théoriquement pas d’appel de marge.

Analyse des profits et des pertes

En supposant que le prix actuel est de 100 USD, 10 contrats courts sur marge de pièces sont ouverts et leur valeur est égale à 100 USD, ce qui est converti en 1 unité de pièce :

  1. Baisse de prix

    • Le prix baisse à 50 USD et le taux de rendement est de : [ \text{Taux de rendement} = \frac{100 - 50}{50} = 100% ] Le nombre de pièces détenues devient 2 et la valeur totale reste : [ 2 \times 50 = 100 , \text{USD} ]
  2. Augmentation des prix

    • Le prix monte à 200 USD et le taux de rendement est de : [ \text{Taux de rendement} = \frac{100 - 200}{200} = -50% ] Le nombre de pièces détenues devient 0,5 et la valeur totale reste : [ 0.5 \times 200 = 100 , \text{USD} ]

Par conséquent, dans une certaine mesure, la valeur totale des ventes à découvert basées sur des devises reste stable, ce qui constitue une opération de préservation de trésorerie. Alors, d’où vient le profit de cette stratégie ? Introduisons le concept suivant :Taux de financement

Taux de financement

Dans la stratégie de vente à découvert basée sur la devise,Taux de financementIl s’agit de l’un des principaux moteurs du rendement d’une stratégie, et ses caractéristiques et ses changements affectent directement la stabilité et la rentabilité de la stratégie. En utilisant correctement les caractéristiques des taux de financement, les stratégies peuvent maintenir de bonnes performances dans différents environnements de marché, mais il est également nécessaire de prêter attention à leurs limites potentielles.

Définition et caractéristiques du taux de financement

Le taux de financement est un mécanisme de régulation du marché des contrats perpétuels, qui vise à équilibrer les coûts de détention des parties longues et courtes et à empêcher le prix du contrat perpétuel de s’écarter du prix spot pendant une longue période. En fait, les amis qui ont étudié le CFA se souviendront encore du nom original du contrat perpétuel, le swap. L’inspiration de conception du mécanisme de taux de financement des contrats perpétuels provient en grande partie du swap de taux d’intérêt dans la finance traditionnelle. Dans un swap de taux d’intérêt, deux parties échangent des paiements d’intérêts à intervalles réguliers sur la base d’un taux d’intérêt convenu (par exemple, taux fixe ou taux variable) pour couvrir le risque de fluctuations des taux d’intérêt. De même, le mécanisme de taux de financement des contrats perpétuels équilibre également les coûts de détention des parties longues et courtes en payant ou en collectant des frais régulièrement, garantissant que l’écart entre le prix du contrat et le prix au comptant ne soit pas trop important.

Mise en œuvre quantitative d’une stratégie d’arbitrage des frais de vente à découvert basée sur les devises

L’introduction du taux de financement vise essentiellement à résoudre le problème de base entre les contrats perpétuels et les prix au comptant. Lorsque le prix du contrat perpétuel est supérieur au prix spot, le taux de financement est positif et les positions longues paient des frais aux positions courtes ; lorsque le prix du contrat perpétuel est inférieur au prix spot, le taux de financement est négatif et les positions courtes paient des frais aux positions longues. Ce mécanisme s’appuie non seulement sur le concept de base des swaps de taux d’intérêt, mais combine également les caractéristiques du marché des devises numériques pour former un outil unique de régulation du marché. Dans le domaine de la monnaie numérique, ses principales caractéristiques sont les suivantes :

  1. L’offre et la demande du marché déterminent:Le taux de financement est déterminé par la relation offre-demande entre les positions longues et courtes sur le marché et est le résultat du jeu entre les forces longues et courtes.
  2. Paiement périodique:Le taux de financement est payé à une certaine période (par exemple 8 heures) et les frais sont transférés entre les positions longues et courtes.
  3. Réflexion émotionnelle:Un taux de financement positif indique généralement que le sentiment du marché est haussier et que le prix du contrat perpétuel est supérieur au prix au comptant ; un taux de financement négatif indique généralement que le sentiment du marché est baissier et que le prix du contrat perpétuel est inférieur au prix au comptant.

Taux de financement positif (taux de financement > 0)

  • Performance:Dans un environnement de taux de financement positif, les longs doivent payer des frais aux shorts.
  • Logique des revenus:Avec le paiement stable du taux de financement, la stratégie continue de collecter des frais de financement en détenant des positions courtes, et même si le prix du marché augmente, cela n’aura pas d’impact négatif significatif sur les rendements. Par exemple, lorsque le taux de financement est de 0,02 %/8 heures, détenir un contrat d’une valeur de 10 000 $ produira le rendement quotidien suivant : [ Chiffre d’affaires journalier = 10 000 \fois 0,02% \times 3 = 6 , \text{USDT} ] Cette source de revenus est relativement stable et moins corrélée aux fluctuations de prix.

Taux de financement négatif (taux de financement < 0)

  • Performance:Lorsque le taux de financement est négatif, les positions courtes doivent payer des frais aux positions longues, et les rendements de la stratégie peuvent être comprimés ou même entraîner des pertes.
  • Points de risque:Lorsque les taux de financement négatifs persistent pendant une longue période ou fluctuent fortement, comme dans un marché baissier prolongé, la stratégie peut être confrontée à des coûts plus élevés en raison du paiement des frais de financement, ce qui fait que le rendement global ne peut pas couvrir les coûts d’exploitation.

Sources de profit stratégiques

Comme l’a dit Maître Zinan, dans la phase initiale de la construction d’une stratégie, il est nécessaire de comprendre les sources de rendement et les risques de la stratégie. Sur la base de ce qui précède, nous comprenons que la valeur totale des ventes à découvert en devise standard doit rester stable, de sorte que la source de revenus finance l’arbitrage des taux. Certains étudiants peuvent être curieux : le taux de financement continuera-t-il à apporter des rendements positifs stables ? Nous effectuons des travaux d’analyse de données à la station internationale 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;

Les paramètres dynamiques utilisent l’échange Binance et le contrat sélectionne le contrat standard Bitcoin (btc_usd) pour afficher le taux de financement cumulé. On peut constater qu’à partir de 2020, les revenus du taux de financement ont affiché une augmentation constante, les revenus cumulés sur cinq ans atteignant 50 %. Bien qu’il ne puisse pas être comparé aux bénéfices de centaines ou de milliers, il est relativement stable, nous pouvons donc trier les sources de bénéfices de cette stratégie.

Dans la stratégie de vente à découvert basée sur les pièces, le taux de financement est la principale source de profit. Étant donné que les unités des contrats à marge en pièces sont fixes, même si les prix du marché fluctuent, les variations de la valeur du contrat pour les vendeurs à découvert sont généralement contrôlables, de sorte que le taux de financement devient la principale source de profit de la stratégie. Voici les effets spécifiques des taux de financement sur les stratégies :

  1. Phase de marché haussier (taux de financement positif)

    • Phénomène de marché:Dans un marché haussier, en raison du sentiment élevé du marché, les investisseurs ont généralement tendance à être longs, ce qui entraîne une augmentation des positions longues, poussant ainsi le taux de financement à une valeur positive.
    • Logique des revenus:Dans ce cas, les vendeurs à découvert bénéficieront du taux de financement payé par les longs, qui deviendra la principale source de profit de la stratégie. Étant donné que le taux de financement est positif, les positions courtes peuvent continuer à générer des bénéfices et, en utilisant le taux de financement obtenu, vous pouvez continuer à ouvrir des positions courtes et obtenir davantage d’avantages en matière de taux de financement.
    • Impact spécifique:Si le taux de financement est positif et stable, les shorts recevront le taux de financement régulièrement et ne seront pas trop affectés par les fluctuations de prix. Même si le prix du marché augmente, les vendeurs à découvert peuvent être confrontés à d’importantes pertes apparentes sur le contrat, mais dans l’ensemble, la valeur nette des fonds reste relativement stable. Cela est dû au fait que la source de profit de la stratégie dépend principalement de la collecte des taux de financement plutôt que des fluctuations de prix. Bien que les fluctuations de prix puissent affecter la perte apparente du contrat, étant donné que les variations de la valeur du contrat de la position courte sont contrôlables, le principal bénéfice des fonds provient toujours de la collecte régulière des taux de financement plutôt que des fluctuations des prix du marché. Cela permet à la stratégie de compenser dans une certaine mesure le risque de fluctuations de prix et de maintenir une appréciation stable des fonds.
  2. Phase de marché baissier (taux de financement négatif)

    • Phénomène de marché:Dans un marché baissier, les prix du marché chutent rapidement et les positions courtes augmentent généralement, ce qui fait que le taux de financement devient négatif, ce qui signifie que les positions courtes doivent payer les positions longues. Toutefois, en raison de l’essor du marché des monnaies numériques ces dernières années, les phases de marché baissier sont relativement rares.
    • Logique des revenus:Bien que le taux de financement soit négatif et que les positions courtes doivent payer des frais, les propriétés de couverture de la stratégie restent valables car les unités des contrats courts sont fixes et la valeur du contrat des positions courtes change peu. Les fluctuations brutales des prix n’entraîneront pas de pertes importantes. Dans le même temps, la charge des taux de financement est relativement contrôlable et la stratégie peut néanmoins rester stable dans une certaine mesure.

Grâce à l’analyse de ces deux environnements de marché, on peut constater que la rentabilité et le risque de la stratégie de vente à découvert basée sur la devise sont principalement affectés par le taux de financement. Lorsque le taux de financement est positif dans le marché haussier, les vendeurs à découvert peuvent en profiter ; tandis que dans le marché baissier, bien que le taux de financement soit négatif, la stratégie a toujours une forte capacité à préserver la valeur car les variations de la valeur du contrat sont contrôlables.

Architecture logique des politiques

Un cadre stratégique solide est la clé de la réussite de la mise en œuvre d’une stratégie. Il fournit un cadre d’exécution clair, garantit que la stratégie peut fonctionner de manière stable dans diverses conditions de marché et gère efficacement les risques et la volatilité. Nous nous référons ici au cadre de stratégie de contrat multidevises basé sur U de Xiaocao Dashen et apportons certaines modifications et améliorations à la norme monétaire.

'''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. Variables globales et description des fonctions

La stratégie est basée sur des définitions de variables simples et met en œuvre des ajouts de positions continues et une surveillance de l’état via des fonctions modulaires.

  • SYMBOLS: Devise d’échange (telle que « BTC »).
  • QUOTO:Devise de base, la devise standard est généralement l’USD.
  • INTERVAL:L’intervalle de temps entre les cycles de politique.
  • ICEMONEY:Montant initial de la commande, utilisé pour les commandes iceberg.
  • ROLLINGNUM:Le nombre de positions ajoutées après le roulement des bénéfices.

2. Modules fonctionnels de base

Voici une brève description de chaque module fonctionnel :

  1. Fonction d’initialisation (InitInfo)
    Utilisé pour charger les informations sur la devise de transaction et le statut initial du compte.

  2. Obtenir des informations de précision (GetPrecision)
    Obtenez la taille minimale de la commande et la valeur du contrat pour chaque paire de trading via l’API d’échange.

  3. Mise à jourTicker
    Obtenez régulièrement les informations actuelles du marché, y compris le meilleur prix acheteur, le meilleur prix vendeur et le dernier prix.

  4. Mises à jour de compte et de position (UpdateAccount, UpdatePosition)
    La synchronisation en temps réel des soldes des comptes et des informations de position fournit une base pour les décisions de trading.

  5. Trading et gestion des commandes (Order, Trade)
    Fonctions unifiées de placement et d’exécution d’ordres, prenant en charge les ordres à cours limité et les ordres au marché.

  6. Surveillance de l’état (UpdateStatus)
    Suivez l’état de la stratégie, y compris les bénéfices et les pertes actuels et les commandes non exécutées.

3. Logique d’ordre de stratégie (MakeOrder)

Le cœur de la stratégie estPosition initiale(Position de l’iceberg) etPosition de roulage(Contrôle par le paramètre de position de roulement ROLLINGNUM). Voici une description détaillée de la logique spécifique :

  1. Vérification de la position initiale:Vérifiez si le solde du compte est supérieur au montant initial d’ouverture de l’iceberg (ICEMONEY). Si les conditions sont remplies, les positions seront ouvertes progressivement par lots afin de réduire les écarts de prix excessifs causés par l’ouverture d’une position en une seule fois.
  2. Stratégie de positionnement en continu:En fonction de la rentabilité du compte (taux de revenu de financement), augmenter raisonnablement la position, optimiser le revenu grâce à l’augmentation continue de la position, afin d’améliorer la rentabilité globale de la stratégie.

Mise en œuvre quantitative d’une stratégie d’arbitrage des frais de vente à découvert basée sur les devises

Selon les résultats du backtesting de la stratégie, nous pouvons constater que la stratégie a obtenu des rendements stables au cours de plusieurs cycles de marché, en particulier dans le marché haussier où le taux de financement est positif depuis longtemps. Cette stratégie est donc, dans une certaine mesure, très adaptée à la gestion de grands fonds. Ses caractéristiques de faible volatilité et de rendements stables peuvent répondre au double besoin des grands fonds en matière de contrôle des risques et de rendements stables. Dans le même temps, la stratégie adopte un effet de levier de 1x, ce qui évite le risque de liquidation causé par un effet de levier élevé et renforce encore sa sécurité.

Analyse des avantages et des inconvénients de la stratégie

avantage

  1. La stratégie est simple et facile à exécuter
    La logique est claire et aucun calcul compliqué n’est requis, ce qui la rend adaptée à la gestion de grands fonds par des fonds spéculatifs ou des investisseurs individuels.

  2. Forte résistance au risque
    L’effet de levier 1x peut éviter le risque de liquidation, et les caractéristiques basées sur la devise garantissent que la valeur du dollar américain reste constante, quelles que soient les grandes fluctuations du marché.

  3. Revenu stable
    Dans un marché haussier, le taux de financement est plus élevé et présente une forte évolutivité, et les devises résultantes peuvent être utilisées pour d’autres investissements (comme le jalonnement).

défaut

  1. Forte dépendance à la monnaie et aux conditions du marché
    Il s’agit d’un défaut. Lorsque le taux de financement d’une devise est positif pendant une longue période (les positions courtes paient les positions longues), comme les contrats BNB, utilisez DATADATA pour sélectionner les contrats basés sur la monnaie BNB. Vous pouvez voir qu’en raison des paramètres de l’échange, le taux de financement s’accumule jusqu’à une valeur négative. De plus, lorsque le grand cycle se situe dans un marché baissier à long terme (2022) et que le taux de financement est négatif, les rendements peuvent ne pas être en mesure de couvrir le coût de fonctionnement de la stratégie.

  1. Manque de rigidité stratégique
    La stratégie actuelle n’inclut pas de logique d’ajustement dynamique, comme l’absence de mesures de réponse (telles que les stratégies de stop-loss ou de take-profit) lors du passage entre les marchés haussiers et baissiers.

  2. Marges bénéficiaires limitées
    Il est adapté aux frais fixes et ne permet pas de capter les rendements excédentaires en cas de fortes fluctuations du marché. Dans certains cas, le rendement n’est pas aussi bon que celui des fonds obligataires traditionnels.

Résumé

La stratégie d’arbitrage de frais de vente à découvert uniques basée sur des pièces de monnaie exploite pleinement les propriétés spéciales des contrats basés sur des pièces de monnaie et offre une solution à faible risque pour la préservation du capital et une appréciation stable. Toutefois, face aux différentes phases du marché, les stratégies doivent faire preuve d’un certain degré de flexibilité pour faire face aux fluctuations des taux de financement et aux risques potentiels. Les orientations d’optimisation futures peuvent inclure :

  1. Ajouter des mesures de gestion dynamiques pour passer d’un marché haussier à un marché baissier ;
  2. Ajuster le rythme d’ajout de postes en fonction des changements dans les taux de financement.

Mais en substance, cette stratégie a certainscontradiction. L’hypothèse initiale de la stratégie est que le marché des devises numériques sera dans un marché haussier à long terme, et que la vente à découvert de contrats basés sur des devises peut être utilisée pour maintenir un flux de trésorerie stable et obtenir des avantages en matière de taux de financement. Cependant, si nous supposons que le marché est dans un marché haussier à long terme, pourquoi ne pas simplement choisir de thésauriser des pièces (hlod) et d’attendre la hausse constante du Bitcoin ? Bien sûr, cette stratégie reste fiable pour ceux qui recherchent des rendements stables. L’objectif de cet article est de présenter cette idée de conception et de fournir un cadre de stratégie d’investissement quantitatif, sur lequel vous pouvez encore l’améliorer et l’optimiser. On espère que cette stratégie pourra devenir un outil efficace pour les investisseurs quantitatifs dans les monnaies numériques.

Références

Comment créer rapidement une stratégie de trading multidevises universelle après la mise à niveau FMZ

Journal des pratiques de trading algorithmique (XIX) - Série d’explications détaillées sur la stratégie d’arbitrage (1) : Arbitrage des frais de vente à découvert basé sur la devise

Conseils utiles:L’investissement est risqué, soyez prudent lorsque vous entrez sur le marché. Il est conseillé aux investisseurs d’allouer leurs fonds de manière raisonnable et de contrôler strictement leurs positions et leur effet de levier sur la base d’une compréhension complète de la logique de la stratégie et des risques, en fonction de leur propre tolérance au risque. Le contenu de cet article est fourni à titre indicatif uniquement et ne constitue aucun conseil en investissement.