主页 > imtoken中国版 > 数字货币跨期套利

数字货币跨期套利

imtoken中国版 2023-02-08 06:55:18

当前时间(2018.7.19)10000 BTC的价值约为5亿人民币。 暂且笔者冒昧的认为,本文的读者在币圈的投入并没有达到这个数字……

所谓挂单和吃单,是指是限价交易还是市价交易。 我们都知道交易所最重要的是流动性。 挂单(place limit orders)可以达到提供流动性的效果,take orders(place market order)可以达到抽取流动性的效果。 这也是下单佣金低于接单佣金的原因。 更有什者,比如Bitmex,下限价单可以获得返利,正是为了鼓励交易者下限价单,鼓励做市,为交易所提供流动性。

因此,根据审慎原则,回测采用taker fee,即0.05%。 第二点是不考虑滑点。 所谓滑点是指由于各种原因,订单价格与我们实时监控并准备下单的价格不一致的情况。 原因有很多,比如:价格变化很快,在监控价格到下单的这段时间内价格已经变化,可能导致不利的情况; 无法满足需求等。 由于我们很难在回测期间获得盘口数据,即使能够获得,也很难完全模拟实际情况。 因此,本文采用的是在平仓时将收益乘以一个系数,大致模拟滑点的发生。

本文主观系​​数为0.9。

第三点是没有考虑资金紧张。 这是一个微妙的点,但却是最重要的一点。 OKEx合约交易的合约号系统在之前的文章中已经简单介绍过,这里将详细介绍。

OKEX合约是OKEX推出的以BTC/LTC等币种结算的虚拟合约产品。 每份合约代表 100 美元的 BTC 或 10 美元的其他货币(LTC、ETH 等)。 买入多头合约以获得虚拟数字货币价格上涨的收益比特币合约收益怎么提取,或卖出空头合约获得虚拟数字货币的收益。 合约的杠杆为10倍或20倍。

——《OKEx合约介绍》

换句话说,买入和卖出是根据合约数量来计算的。 与传统期货合约不同,一份合约不是具体数量的“标的”,而是价值特定金额美元的“标的”,而保证金就是合约标的的现货。 本文以合约标的使用的保证金为 EOS 。 合约之所以这样设计的原因是:

传统的比特币虚拟合约以美元计价,每份合约代表固定数量的比特币。 这种合约最大的问题是它的杠杆会随着价格的变化而变化,从而产生两个副作用: 难度 套期保值和套利不能做长期合约。

针对以上问题,OKEX在设计虚拟合约时做出了相应的调整。 每份合约代表价值 100 美元的比特币。 这种设计使得虚拟合约的杠杆始终稳定在一个固定值,有利于对冲和套利。

OKEX比特币虚拟合约的杠杆以法币收益水平稳定杠杆表示:投资100美元,可获得的收益=100美元*比特币涨跌*固定杠杆倍数。

假设当前价格为500USD/BTC,投资者以当前价格买入1个BTC,本金为500USD。 此时,投资者可以购买 50 BTC 虚拟合约。 此时,如果BTC价格上涨到750美元,上涨50%,投资者的合约收益为3.3333 BTC。 以目前的价格卖出后,他可以获得 2500 美元,这是本金投资的 5 倍。 如果价格上涨到1000美元,合约收益为5BTC,卖出后的美元收益为5000美元,是其美元收益的10倍。 无论价格如何波动,合约的杠杆都非常稳定,方便商家使用合约进行套期保值,也方便普通投资者进行持仓管理。

——《OKEx合约介绍》

所以下单的单位是按张数计算的,EOS每张10美元。 也就是说,每笔订单至少价值 10 美元的 EOS。 这将导致如果账户中的钱没有被100%使用。从距离来看,目前EOS的每周合约价格为8.43美元,交易者手中有657个EOS,下单数量为

int(657\times8.43\div10)

那是553张。 剩余的EOS不能作为下单的保证金,因为数量不够。

考虑到这三点,前文中数字货币跨期套利(回测·简易版)的方法过于粗糙,一般来说会高估收益。

# ===正确的回测思路和代码

其实仓位的生成没有什么大问题,根据仓位生成的交易信号也不需要改变。 与上一篇相比,唯一需要改变的部分是收入的计算。 这一次,我们采取模拟交易的方式。

首先,将手中的USDT换成EOS(包含在手续费中),利用远期合约对冲EOS(包含在手续费中),防止在持仓不对时出现价格波动的风险打开。 当获得开仓信号时,程序会计算当前持有的eos数量,根据相应的比例计算每张合约应开仓的合约数量,并记录成交价格(包含在手续费中); 根据持仓价格和合约数量计算每张合约的盈亏(包括手续费和滑点),得到本次开仓平仓操作收益的EOS,用季度合约控制下一期前的仓位发出开仓信号。 部分EOS进行对冲(包含在手续费中),防止价格波动带来的风险; 未获得信号时,计算合约未实现盈亏,计算当前美元价值。 回测结束后清仓,计算最终EOS及其USD价值。

代码如下:

配置部分

# -*- coding=utf-8 -*-
import os
# 获取当前程序的地址
current_file = __file__
# 程序根目录地址
root_path = os.path.abspath(os.path.join(current_file, os.pardir, os.pardir))
# 输入数据根目录地址
input_data_path = os.path.abspath(os.path.join(root_path, 'data', 'input_data'))
# 输出数据根目录地址
output_data_path = os.path.abspath(os.path.join(root_path, 'data', 'output_data'))

功能部分

# -*- coding:utf-8 -*-
import pandas as pd
import os
from program import config
commission = 0.0005
pd.set_option('expand_frame_repr', False)
# 获取数据
def get_data():
    for roots, dirs, files in os.walk(config.input_data_path):
        if files:
            if files[0].startswith('okex_spot_future'):
                file_name = files[0]
    data_path = os.path.join(config.input_data_path, file_name)
    df = pd.read_csv(data_path)
    return(df)
# 产生网格
def gen_grid(number, start, down_step, up_step):
    grid_list = []
    for i in range(number):
        grid_list.append({'down': start + i * down_step, 'up': start + (i+1) * up_step})
    return grid_list
# 计算仓位
def posit (df_sample, number, grid_list):
    '''
    :param df_sample:
    :param number: 网格数量
    :param start_point: 起始点
    :return:
    '''
    for i in range(number):
        for indexs in df_sample.index:
            # 价差大于建仓阈值
            condition1 = (df_sample.at[indexs, 'gap'] >= grid_list[i]['up'])
            if condition1:
                df_sample.at[indexs, 'l_%d_position' % i] = 1
            # 价差小于平仓阈值
            condition2 = (df_sample.at[indexs, 'gap'] <= grid_list[i]['down'])
            if condition2:
                df_sample.at[indexs, 'l_%d_position' % i] = 0
            # 周五下午4:00强制平仓
            condition3 = (df_sample.at[indexs,'candle_begin_time'].weekday() == 4)and\
                         (df_sample.at[indexs,'candle_begin_time'].hour == 15)and\
                         (df_sample.at[indexs, 'candle_begin_time'].minute == 59) and\
                         (df_sample.at[indexs, 'candle_begin_time'].second == 00)
            if condition3:
                df_sample.at[indexs, 'l_%d_position' % i] = 0
            # 最后一分钟,强平
            condition4 = (indexs == (df_sample.shape[0]-1))
            if condition4:
                df_sample.at[indexs, 'l_%d_position' % i] = 0
    df_sample.fillna(method = 'ffill', inplace = True)
    df_sample.fillna(0, inplace=True)
    return(df_sample)
# 计算单个合约收益
def cal_yield(amount, open_price, settle_price, type):
    '''
    :param amount: 张数
    :param open_price: 开仓价
    :param settle_price: 结算价
    :param type: 合约方向
    :return:
    '''
    if open_price != 0:
        if type == 'long':
            earned = amount * (10/open_price - 10/settle_price) * (1-commission)
        if type == 'short':
            earned = amount * (10/settle_price - 10/open_price) * (1-commission)
        return(earned)
    else:
        return(0)
# 调仓
def change(equity, type, spot_price, week_price, quarter_price):
    '''
    :param equity: {'long_amount':0, 'short_amount':0, 'hedge_amount':0, 'week_open_price':0, 'quarter_open_price':0, 'eos':currency}
    :param type:
    :param spot_price:
    :param week_price:
    :param quarter_price:
    :return:
    '''
    # 开仓,记录信息
    if type == 'open':
        equity['week_open_price'] = week_price
        equity['quarter_open_price'] = quarter_price
        long_margin = equity['eos'] * 19 / 40
        short_margin = equity['eos'] * 19 / 40
        hedge_margin = equity['eos'] * 2 / 40
        equity['long_amount'] = int(long_margin * 20 * week_price * (1-commission) / 10) # 当周开仓张数
        equity['short_amount'] = int(short_margin * 20 * quarter_price * (1-commission) / 10) # 季度开仓张数
        equity['hedge_amount'] = int(hedge_margin * 20 * quarter_price * (1-commission) / 10) # 对冲开仓张数
        equity['eos'] *= (1 - commission)
    # 平仓
    if type == 'close':
        earned_week = cal_yield(equity['long_amount'], equity['week_open_price'], week_price, 'long')
        earned_quarter = cal_yield(equity['short_amount'], equity['quarter_open_price'], quarter_price, 'short')
        earned_hedge = cal_yield(equity['hedge_amount'], equity['quarter_open_price'], quarter_price, 'short')
        equity['long_amount'] = 0
        equity['short_amount'] = 0
        equity['hedge_amount'] = 0
        equity['week_open_price'] = 0
        equity['quarter_open_price'] = 0
        equity['eos'] += (earned_week + earned_quarter + earned_hedge) * 0.9
    # 对冲
    if type == 'hedge':
        equity['week_open_price'] = week_price
        equity['quarter_open_price'] = quarter_price
        hedge_margin = equity['eos'] / 20
        equity['long_amount'] = 0 # 当周开仓张数
        equity['short_amount'] = 0 # 季度开仓张数
        equity['hedge_amount'] = int(hedge_margin * 20 * quarter_price * (1-commission) / 10) # 对冲开仓张数
        equity['eos'] = (equity['eos'] - hedge_margin) + hedge_margin * (1-commission)
    return equity
# 计算资金曲线完整版
def equity_curve_complete(df_sample, principal, number):
    '''
    :param df_sample:
    :param principal: 本金
    :param number: 账户数量
    :return:
    '''
    # 每个账户的初始资金,usdt
    money_each = principal / number
    # 逐个账户遍历
    for account in range(number):
        # 买币
        commision = 0.0005
        currency = money_each / df_sample.iloc[0,1] * (1- commision)
        # usdt_left = 0 # 剩余usdt为0
        equity = {'long_amount':0, 'short_amount':0, 'hedge_amount':0, 'week_open_price':0, 'quarter_open_price':0, 'eos':currency}
        # 如果初始仓位为1,建仓
        if df_sample.at[0, 'l_%d_position' % account] == 1:
            equity = change(equity, 'open', df_sample.iloc[0, 1], df_sample.iloc[0, 2], df_sample.iloc[0, 3])
        # 如果初始仓位为0,买入季度合约对冲保证金,记录在equity的hedge里
        if df_sample.at[0, 'l_%d_position' % account] == 0:
            equity = change(equity, 'hedge', df_sample.iloc[0, 1], df_sample.iloc[0, 2], df_sample.iloc[0, 3])
        df_sample.at[0, 'l_%d_eos' % account] = equity['eos']
        # 模拟该账户的持仓变化
        for indexs in df_sample.index:
            spot_price = df_sample.at[indexs, 'EOS_cash_close']
            week_price = df_sample.at[indexs, 'EOS_this_week_close']
            quarter_price = df_sample.at[indexs, 'EOS_quarter_close']
            # 不是第一行的部分,模拟交易
            if indexs > 0:
                # 如果仓位和昨天不同,进行调仓
                if df_sample.at[indexs,'l_%d_position' % account] != df_sample.at[indexs-1,'l_%d_position' % account]:
                    # 今天仓位为1,建仓
                    if df_sample.at[indexs, 'l_%d_position' % account] == 1:
                        # 先平掉所有持仓
                        equity = change(equity, 'close', spot_price, week_price, quarter_price)
                        # 建仓
                        equity = change(equity, 'open', spot_price, week_price, quarter_price)
                        # 记录
                        df_sample.at[indexs, 'l_%d_eos' % account] = equity['eos']
                    # 今天仓位为0,平仓
                    if df_sample.at[indexs, 'l_%d_position' % account] == 0:
                        # 平掉所有持仓
                        equity = change(equity, 'close', spot_price, week_price, quarter_price)
                        # 对冲
                        equity = change(equity, 'hedge', spot_price, week_price, quarter_price)
                        # 记录
                        df_sample.at[indexs, 'l_%d_eos' % account] = equity['eos']
                # 如果仓位和昨天相同,计算当前合约持仓盈亏
                if df_sample.at[indexs, 'l_%d_position' % account] == df_sample.at[indexs-1, 'l_%d_position' % account]:
                    # 计算未实现盈亏
                    earned_week = cal_yield(equity['long_amount'], equity['week_open_price'], week_price, 'long')
                    earned_quarter = cal_yield(equity['short_amount'], equity['quarter_open_price'], quarter_price, 'short')
                    earned_hedge = cal_yield(equity['hedge_amount'], equity['quarter_open_price'], quarter_price, 'short')
                    df_sample.at[indexs, 'l_%d_eos' % account] = equity['eos'] + earned_week + earned_quarter + earned_hedge
    # 计算总eos和usd总价值
    for indexs in df_sample.index:
        sum = 0
        for account in range(number):
            sum += df_sample.at[indexs, 'l_%d_eos' % account]
        df_sample.at[indexs, 'total_eos'] = sum
        df_sample.at[indexs, 'total_usd'] = sum * df_sample.at[indexs, 'EOS_cash_close']
    return(df_sample)

主程序部分

# -*- coding:utf-8 -*-
import pandas as pd
from program import function as fct
from program import config
pd.set_option('expand_frame_repr', False)
# 读取数据
df = fct.get_data()
df = df.iloc[25920:] # 只用数据的后半部分进行回测,因为前半部分用来推测网格参数了
df.reset_index(inplace = True, drop = True)
# 获取交易合约的品种
sample_list = []
for keys in df:
    if keys.endswith('close'):
        if keys[:3] not in sample_list:
            sample_list.append(keys[:3])
# 对每个品种进行回测
sample_list = ['EOS']
for sample in sample_list:
    # 获取df中该sample的部分
    df_sample = df[['candle_begin_time', sample + '_cash_close', sample +'_this_week_close', sample + '_quarter_close']]
    # 把日期转换为时间变量
    df_sample['candle_begin_time']=pd.to_datetime(df_sample['candle_begin_time'])
    # 计算价差
    df_sample['gap'] = (df[sample + '_quarter_close'] - df[sample +'_this_week_close']) / df[sample +'_this_week_close']
    # 网格参数
    number = 5  # 网格数量
    start_point = 0  # 网格最低点
    down_step = 0.01  # 下界步长
    up_step = 0.01 # 上界步长
    # 产生网格
    grid_list = fct.gen_grid(number, start_point, down_step, up_step)
    print(grid_list)
    # 计算仓位
    df_sample = fct.posit(df_sample, number, grid_list)
    # 计算资金曲线 完整版
    principal = 1000000
    df_sample = fct.equity_curve_complete(df_sample, principal, number)
    print(df_sample)
    df_sample.to_csv(config.output_data_path + '/curve.csv')

# ===回测真实结果

最终回测得到的资金曲线如下:

比特币50倍合约怎么玩_比特币合约收益怎么提取_比特币合约交易教程

其中最引人注目的是存在巨大的回撤。 这是因为当时的价差一直在上涨,扩大到10%以上,明显超过了我们定义的5%。 但是,在满仓模式下,没有强平。 价差的扩大是不可持续的。 同时,如果价差扩大到比特币合约收益怎么提取,比如15%,导致网格交易账户整体爆仓,那么单纯做空价差也会变得非常赚钱。 一旦15%的价差缩小到2%左右,就会有130%的回报。 也就是说,将新资金投入做空价差将是另一种盈利足以弥补网格交易损失的策略。

最终回测收益在14%左右,比上一篇文章的20%多要低很多,但还是很高的。 之所以能在短短半个月的时间里赚到如此巨额的利润,就是差价的波动。

# ===总结

网格交易本质上是放弃了对当前点差头寸的判断,从点差的波动中获利。 收益降低了,风险也降低了。能够准确判断趋势当然最好,但是当你不确定自己是否正确时,“赚小钱赢率高”就是量化的意思