2
Seguir
20
Seguidores

Implementación cuantitativa de una estrategia de arbitraje de comisiones por ventas en corto basada en divisas

Creado el: 2025-01-21 17:06:52, Actualizado el: 2025-02-17 11:25:01
comments   0
hits   452

Implementación cuantitativa de una estrategia de arbitraje de comisiones por ventas en corto basada en divisas

Imagine tener una estrategia que pueda permanecer estable en medio de las fuertes fluctuaciones del mercado de criptomonedas y que pueda brindarle retornos positivos sostenidos independientemente de los mercados alcistas o bajistas. ¿Suena como una fantasía? En realidad no lo es. La estrategia de arbitraje de vender en corto la moneda pagando una comisión equivalente a una sola vez es una herramienta mágica para ganar dinero sin hacer nada.

Al utilizar inteligentemente las propiedades únicas de los contratos basados ​​en monedas y el mecanismo de tasa de financiación, esta estrategia no solo puede obtener retornos estables en un mercado alcista, sino también evitar eficazmente los riesgos en un mercado bajista, logrando retornos constantes a lo largo de los ciclos del mercado. La naturaleza “protegida en efectivo” de los contratos basados ​​en monedas garantiza que el valor total de la estrategia permanezca estable incluso si los precios del mercado fluctúan significativamente. La tasa de financiación, como mecanismo central de los contratos perpetuos, proporciona una fuente adicional de ingresos para la estrategia. Este artículo analizará en profundidad la lógica central, el proceso de implementación, las ventajas y desventajas de la estrategia de venta en corto basada en monedas para ayudar a los inversores a comprender cómo lograr “ingresos pasivos” a través de esta estrategia en el mercado de divisas digitales. Independientemente de si es un novato en el comercio cuantitativo o un inversor experimentado, vale la pena comprender y probar en profundidad esta estrategia.

Venta en corto basada en monedas

Características del patrón monetario

La unidad del contrato con margen de moneda se mide en hojas, y el valor de cada hoja es fijo (por ejemplo, 1 contrato de BTC vale 100 USD y 10 USD de ETH). Esta característica significa que, en el caso de un apalancamiento de 1x, incluso si el precio del mercado fluctúa mucho, teóricamente no habrá ninguna llamada de margen.

Análisis de pérdidas y ganancias

Suponiendo que el precio actual es 100 USD, se abren 10 contratos cortos con margen de moneda y su valor es igual a 100 USD, que se convierte en 1 unidad de moneda:

  1. Bajada de precio

    • El precio baja a 50 USD y la tasa de retorno es: [ \text{Tasa de retorno} = \frac{100 - 50}{50} = 100% ] El número de monedas retenidas pasa a ser 2 y el valor total permanece: [ 2 \times 50 = 100 , \text{USD} ]
  2. Aumento de precios

    • El precio sube a 200 USD y la tasa de retorno es: [ \text{Tasa de retorno} = \frac{100 - 200}{200} = -50% ] La cantidad de monedas retenidas pasa a ser 0,5 y el valor total permanece: [ 0.5 \times 200 = 100 , \text{USD} ]

Por lo tanto, hasta cierto punto, el valor total de las ventas en corto basadas en divisas permanece estable, lo que constituye una operación de preservación de efectivo. ¿De dónde proviene entonces el beneficio de esta estrategia? Introduzcamos el siguiente concepto:Tasa de financiación

Tasa de financiación

En la estrategia de venta en corto basada en divisas,Tasa de financiaciónEs uno de los principales impulsores del rendimiento de la estrategia, y sus características y cambios afectan directamente la estabilidad y la rentabilidad de la estrategia. Al utilizar adecuadamente las características de las tasas de financiamiento, las estrategias pueden mantener un buen desempeño en diferentes entornos de mercado, pero también es necesario prestar atención a sus posibles limitaciones.

Definición y características de la tasa de financiación

La tasa de financiación es un mecanismo regulador en el mercado de contratos perpetuos, que tiene como objetivo equilibrar los costos de tenencia de las partes largas y cortas y evitar que el precio del contrato perpetuo se desvíe del precio al contado durante un largo tiempo. De hecho, los amigos que han estudiado CFA todavía recordarán el nombre original del contrato perpetuo: swap. La inspiración del diseño del mecanismo de tasa de financiamiento de los contratos perpetuos se deriva en gran medida del swap de tasas de interés en las finanzas tradicionales. En un swap de tasas de interés, dos partes intercambian pagos de intereses a intervalos regulares basados ​​en una tasa de interés acordada (por ejemplo, tasa fija vs. tasa flotante) para cubrir el riesgo de fluctuaciones en las tasas de interés. De manera similar, el mecanismo de tasa de financiamiento de los contratos perpetuos también equilibra los costos de tenencia de las partes largas y cortas pagando o cobrando tarifas regularmente, lo que garantiza que la brecha entre el precio del contrato y el precio al contado no sea demasiado grande.

Implementación cuantitativa de una estrategia de arbitraje de comisiones por ventas en corto basada en divisas

La introducción de la tasa de financiación tiene como objetivo esencial resolver el problema de la base entre los contratos perpetuos y los precios al contado. Cuando el precio del contrato perpetuo es más alto que el precio al contado, la tasa de financiación es positiva y los largos pagan comisiones a los cortos; cuando el precio del contrato perpetuo es más bajo que el precio al contado, la tasa de financiación es negativa y los cortos pagan comisiones a los largos. Este mecanismo no solo se basa en el concepto central de los swaps de tasas de interés, sino que también combina las características del mercado de divisas digitales para formar una herramienta única de regulación del mercado. En el campo de las monedas digitales, sus principales características incluyen:

  1. La oferta y la demanda del mercado determinan:La tasa de financiación está determinada por la relación de oferta y demanda entre posiciones largas y cortas en el mercado y es el resultado del juego entre fuerzas largas y cortas.
  2. Pago periódico:La tasa de financiación se paga en un período determinado (por ejemplo, 8 horas) y las tarifas se transfieren entre posiciones largas y cortas.
  3. Reflexión emocional:Una tasa de financiación positiva generalmente indica que el sentimiento del mercado es alcista y el precio del contrato perpetuo es más alto que el precio al contado; una tasa de financiación negativa generalmente indica que el sentimiento del mercado es bajista y el precio del contrato perpetuo es más bajo que el precio al contado.

Tasa de financiación positiva (tasa de financiación > 0)

  • Actuación:En un entorno de tasas de financiación positivas, los inversores que operan en posiciones largas deben pagar comisiones a los inversores que operan en posiciones cortas.
  • Lógica de ingresos:Con el pago estable de la tasa de financiación, la estrategia continúa cobrando tarifas de financiación manteniendo posiciones cortas, e incluso si el precio del mercado aumenta, no tendrá un impacto negativo significativo en los rendimientos. Por ejemplo, cuando la tasa de financiación es del 0,02 %/8 horas, mantener un contrato valorado en $10 000 producirá el siguiente rendimiento diario: [ Ingresos diarios = 10.000 \times 0,02% \times 3 = 6 , \text{USDT} ] Esta fuente de ingresos es relativamente estable y está menos correlacionada con las fluctuaciones de precios.

Tasa de financiación negativa (tasa de financiación < 0)

  • Actuación:Cuando la tasa de financiación es negativa, las posiciones cortas deben pagar tarifas a las posiciones largas y los rendimientos de la estrategia pueden comprimirse o incluso resultar en pérdidas.
  • Puntos de riesgo:Cuando las tasas de financiación negativas persisten durante mucho tiempo o fluctúan mucho, como en un mercado bajista prolongado, la estrategia puede enfrentar costos más altos debido al pago de tarifas de financiación, lo que da como resultado que el rendimiento general no pueda cubrir los costos operativos.

Fuentes de beneficios estratégicos

Como dijo el Maestro Zinan, en la etapa inicial de construcción de la estrategia, es necesario comprender las fuentes de retorno y los riesgos de la estrategia. Con base en lo anterior, entendemos que el valor total de las ventas en corto en moneda estándar debe permanecer estable, por lo que la fuente de ingresos es el arbitraje de tasas de financiación. Algunos estudiantes pueden sentir curiosidad: ¿la tasa de financiación seguirá generando rendimientos positivos estables? Realizamos trabajos de análisis de datos en la Estación Internacional 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;

Los parámetros dinámicos utilizan el intercambio de Binance y el contrato selecciona el contrato estándar de Bitcoin (btc_usd) para mostrar la tasa de financiación acumulada. Se puede observar que desde 2020 hasta el presente, los ingresos por tasa de financiamiento han mostrado un nivel en constante aumento, y los ingresos acumulados de cinco años alcanzan el 50%. Aunque no se puede comparar con las ganancias de cientos o miles, es relativamente estable, por lo que podemos ordenar las fuentes de ganancias de esta estrategia.

En la estrategia de venta en corto basada en monedas, la tasa de financiación es la fuente clave de ganancias. Dado que las unidades de los contratos con margen de monedas son fijas, incluso si los precios del mercado fluctúan, los cambios en el valor del contrato para los vendedores en corto suelen ser controlables, por lo que la tasa de financiación se convierte en la principal fuente de ganancias para la estrategia. Los siguientes son los efectos específicos de las tasas de financiación sobre las estrategias:

  1. Fase de mercado alcista (la tasa de financiación es positiva)

    • Fenómeno de mercado:En un mercado alcista, debido al alto sentimiento del mercado, los inversores generalmente tienden a comprar, lo que resulta en un aumento de las posiciones largas, empujando así la tasa de financiación a un valor positivo.
    • Lógica de ingresos:En este caso, los vendedores en corto se beneficiarán de la tasa de financiación pagada por los vendedores en largo, que se convertirá en la principal fuente de ganancias para la estrategia. Dado que la tasa de financiación es positiva, las posiciones cortas pueden seguir generando ganancias y, al utilizar la tasa de financiación obtenida, puede seguir abriendo posiciones cortas y obtener más beneficios de la tasa de financiación.
    • Impacto específico:Si la tasa de financiación es positiva y estable, los cortos recibirán la tasa de financiación regularmente y no se verán afectados demasiado por las fluctuaciones de precios. Incluso si el precio del mercado aumenta, los vendedores en corto pueden enfrentar grandes pérdidas aparentes en el contrato, pero en general, el valor neto de los fondos permanece relativamente estable. Esto se debe a que la fuente de ganancias de la estrategia depende principalmente de la recaudación de tasas de financiación más que de las fluctuaciones de precios. Si bien las fluctuaciones de precios pueden afectar la pérdida aparente del contrato, dado que los cambios en el valor del contrato de la posición corta son controlables, la ganancia principal de los fondos aún proviene de la recaudación regular de las tasas de financiamiento en lugar de las fluctuaciones de los precios del mercado. Esto permite que la estrategia compense hasta cierto punto el riesgo de fluctuaciones de precios y mantenga una apreciación estable de los fondos.
  2. Fase de mercado bajista (tasa de financiación negativa)

    • Fenómeno de mercado:En un mercado bajista, los precios del mercado caen rápidamente y las posiciones cortas suelen aumentar, lo que hace que la tasa de financiación se vuelva negativa, lo que significa que los cortos deben pagar a los largos. Sin embargo, debido al auge del mercado de monedas digitales en los últimos años, las fases de mercado bajista son relativamente raras.
    • Lógica de ingresos:Aunque la tasa de financiación es negativa y los vendedores en corto deben pagar comisiones, las características de cobertura de la estrategia siguen siendo válidas porque la unidad del contrato corto es fija y el valor del contrato de la posición corta cambia poco. Las fluctuaciones violentas de los precios no provocarán grandes pérdidas. Al mismo tiempo, la carga de las tasas de financiación es relativamente controlable y la estrategia puede seguir siendo estable hasta cierto punto.

A través del análisis de estos dos entornos de mercado, se puede ver que la rentabilidad y el riesgo de la estrategia de venta en corto basada en divisas se ven afectados principalmente por la tasa de financiación. Cuando la tasa de financiación es positiva en el mercado alcista, los vendedores en corto pueden beneficiarse de ella; mientras que en el mercado bajista, aunque la tasa de financiación es negativa, la estrategia todavía tiene una fuerte capacidad para preservar el valor porque los cambios en el valor del contrato son controlables.

Arquitectura de lógica de políticas

Un marco de estrategia sólido es la clave para la implementación exitosa de una estrategia. Proporciona un marco de ejecución claro para garantizar que la estrategia pueda operar de manera estable en diversas condiciones de mercado y lidiar de manera eficaz con los riesgos y la volatilidad. Aquí nos referimos al marco de estrategia de contrato multidivisa basado en U de Xiaocao Dashen y realizamos ciertas modificaciones y mejoras al estándar monetario.

'''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 y descripción de funciones

La estrategia se basa en definiciones de variables simples e implementa adiciones de posiciones sucesivas y monitoreo de estado a través de funciones modulares.

  • SYMBOLS: Comercio de divisas (como “BTC”).
  • QUOTO:La moneda base, la moneda estándar, suele ser el dólar estadounidense.
  • INTERVAL:El intervalo de tiempo entre ciclos de políticas.
  • ICEMONEY:Monto del pedido inicial, utilizado para pedidos de iceberg.
  • ROLLINGNUM:El número de posiciones agregadas después de obtener ganancias.

2. Módulos funcionales básicos

A continuación se presenta una breve descripción de cada módulo funcional:

  1. Función de inicialización (InitInfo)
    Se utiliza para cargar información sobre la moneda de la transacción y el estado inicial de la cuenta.

  2. Obtener información precisa (GetPrecision)
    Obtenga el tamaño mínimo de pedido y el valor del contrato para cada par comercial a través de la API de intercambio.

  3. ActualizarTicker
    Obtenga periódicamente la información actual del mercado, incluido el mejor precio de oferta, el mejor precio de venta y el último precio.

  4. Actualizaciones de cuenta y posición (UpdateAccount, UpdatePosition)
    La sincronización en tiempo real de los saldos de cuentas y la información de posición proporciona una base para las decisiones comerciales.

  5. Gestión de órdenes y operaciones (Orden, Operaciones)
    Funciones unificadas de colocación y ejecución de órdenes, compatibles con órdenes limitadas y órdenes de mercado.

  6. Monitoreo de estado (UpdateStatus)
    Realice un seguimiento del estado de la estrategia, incluidas las ganancias y pérdidas actuales y los pedidos no completados.

3. Lógica de orden de estrategia (MakeOrder)

El núcleo de la estrategia esPosición inicial(Posición del iceberg) yPosición de rodadura(Controlado por el parámetro de posición rodante ROLLINGNUM). A continuación se muestra una descripción detallada de la lógica específica:

  1. Comprobación de la posición inicial:Verifique si el saldo de la cuenta es mayor que el monto de apertura inicial del iceberg (ICEMONEY). Si se cumplen las condiciones, las posiciones se abrirán gradualmente en lotes para reducir el deslizamiento excesivo de precios causado por la apertura de una posición de una sola vez.
  2. Estrategia de posición de rodadura:De acuerdo con la rentabilidad de la cuenta (ingresos por tasa de financiación), aumente la posición razonablemente, optimice los ingresos mediante el aumento continuo de la posición, a fin de mejorar la rentabilidad general de la estrategia.

Implementación cuantitativa de una estrategia de arbitraje de comisiones por ventas en corto basada en divisas

Según los resultados del backtesting de la estrategia, podemos ver que la estrategia ha logrado retornos estables en múltiples ciclos de mercado, especialmente en el mercado alcista donde la tasa de financiación ha sido positiva durante mucho tiempo. Por lo tanto, esta estrategia es muy adecuada para la gestión de grandes fondos hasta cierto punto. Sus características de baja volatilidad y retornos estables pueden satisfacer la doble necesidad de los grandes fondos en cuanto a control de riesgos y retornos estables. Al mismo tiempo, la estrategia adopta un apalancamiento de 1x, lo que evita el riesgo de liquidación causado por un alto apalancamiento y mejora aún más su seguridad.

Análisis de las ventajas y desventajas de la estrategia

ventaja

  1. La estrategia es sencilla y fácil de ejecutar.
    La lógica es clara y no se requieren cálculos complicados, lo que lo hace adecuado para la gestión de grandes fondos por parte de fondos de cobertura o inversores individuales.

  2. Fuerte resistencia al riesgo
    El apalancamiento de 1x puede evitar el riesgo de liquidación, y las características basadas en la moneda garantizan que el valor del dólar estadounidense permanezca constante, independientemente de las grandes fluctuaciones del mercado.

  3. Ingresos estables
    En un mercado alcista, la tasa de financiación es más alta y tiene una fuerte escalabilidad, y las monedas resultantes se pueden utilizar para otras inversiones (como el staking).

defecto

  1. Fuerte dependencia de la moneda y de las condiciones del mercado
    Esto es un error. Cuando la tasa de financiación de una moneda es positiva durante un largo tiempo (las posiciones cortas pagan a las largas), como en los contratos BNB, utilice DATADATA para seleccionar contratos basados ​​en monedas BNB. Puede ver que, debido a la configuración del exchange, la tasa de financiación se acumula hasta un valor negativo. Además, cuando el gran ciclo se produce en un mercado bajista de largo plazo (2022) y la tasa de financiación es negativa, los rendimientos pueden no ser capaces de cubrir el coste de operación de la estrategia.

  1. Falta de rigidez de la estrategia
    La estrategia actual no incluye una lógica de ajuste dinámico, como la falta de medidas de respuesta (como estrategias de stop-loss o take-profit) al cambiar entre mercados alcistas y bajistas.

  2. Márgenes de beneficio limitados
    Es adecuado para cobrar comisiones “planas” y no puede captar rendimientos excedentes en grandes fluctuaciones del mercado. En algunos casos, la tasa de rendimiento no es tan buena como la de los fondos de bonos tradicionales.

Conclusión

La estrategia de arbitraje de tarifa de venta en corto única basada en monedas aprovecha al máximo las propiedades especiales de los contratos basados ​​en monedas y proporciona una solución de bajo riesgo para la preservación del capital y la apreciación estable. Sin embargo, ante las diferentes etapas del mercado, las estrategias deben tener un cierto grado de flexibilidad para hacer frente a las fluctuaciones en las tasas de financiamiento y los riesgos potenciales. Las futuras direcciones de optimización pueden incluir:

  1. Añadir medidas de gestión dinámica para el cambio de mercados alcistas a bajistas;
  2. Ajustar el ritmo de adición de posiciones según los cambios en las tasas de financiación.

Pero en esencia, esta estrategia tiene ciertascontradicción. El supuesto inicial de la estrategia es que el mercado de divisas digitales estará en un mercado alcista a largo plazo y que las posiciones cortas en contratos basados ​​en divisas se pueden utilizar para mantener un flujo de caja estable y obtener beneficios en la tasa de financiación. Sin embargo, si asumimos que el mercado está en un mercado alcista a largo plazo, ¿por qué no optar simplemente por acumular monedas (hlod) y esperar el aumento constante de Bitcoin? Por supuesto, esta estrategia sigue siendo confiable para quienes buscan rendimientos estables. El objetivo de este artículo es presentar esta idea de diseño y proporcionar un marco de estrategia de inversión cuantitativa, sobre el cual pueda mejorarla y optimizarla aún más. Se espera que esta estrategia pueda convertirse en una herramienta eficaz para los inversores cuantitativos en monedas digitales.

Referencias

Cómo crear rápidamente una estrategia de trading multidivisa universal después de actualizar FMZ

Diario de práctica de trading algorítmico (19) - Serie de explicaciones detalladas sobre estrategias de arbitraje (1): Arbitraje de comisiones por ventas en corto basado en divisas

Buenos consejos:La inversión es riesgosa, tenga cuidado al ingresar al mercado. Se aconseja a los inversores que asignen fondos de manera razonable y controlen estrictamente las posiciones y el apalancamiento basándose en una comprensión completa de la lógica de la estrategia y los riesgos, de acuerdo con su propia tolerancia al riesgo. El contenido de este artículo es sólo de referencia y no constituye ningún consejo de inversión.