主页 > imtoken钱包网址 > 【币圈小测】期货与现货套利(上)——期限套利原理

【币圈小测】期货与现货套利(上)——期限套利原理

imtoken钱包网址 2023-04-18 07:35:44

大家好! 我是币圈九哥,匆匆入场,匆匆入厂……温馨提示,本文不构成任何投资建议,仅供学习分享。 本期为大家带来的策略有:期限套利、永续合约套利资金费率低,适合新手!

文章目录

一、套现原则 1.1 永续合约

永续合约是加密货币交易市场中的一种特殊期货合约。 没有有效期。 为了保持永续合约与现货价格的解耦,引入“资金费率”机制,让无交割日的永续合约与现货价格之间的价差可以由此收敛,而不会过度解耦.

1.2 资金费率

资金费率的设计是为了防止期货价格无限期地偏离现货价格过远。 当市场长线情绪偏强时,多方需要向空方支付资金费率,这样使得期货价格背离现货价格的多方就会产生持仓成本。 相反,如果做空情绪浓厚,则做空方将向做多方支付资金费率。

1.3 套利机会

资金费率不是交易者支付给交易所的手续费,而是交易双方在永续合约上做多做空时需要互相支付的持有费。 在加密货币市场的特殊机制背景下,出现了新的套利机会:

永续合约的基准利率为每八小时0.01%,根据市场情况在-0.75%至0.75%之间变动。

1.4 具体例子

以BTC为例,如果用10000USDT进行现货套利,假设当BTC为10000USDT时,可以进行如下操作:

1.5 收入放大

为了提高整体资金利用率,我们可以在合约市场中适当使用杠杆。 如果我们使用2倍杠杆,我们还可以利用上述资金进行套利。 在现货市场,我们可以购买 6666.6 USDT 的 BTC(0.666 BTC)。 合约市场做空0.666 BTC,因为使用了2倍杠杆,此时的保证金只有3333.3 USDT。 如果当前费率为0.05%,BTC价格为10,000 USDT,那么您将获得0.666 * 10,000 * 0.05% = 3.333 USDT的资金费,比没有杠杆时多33%。 在2倍杠杆的情况下期现套利btc期现套利btc,年化率提升至36.46%; 在 3 倍杠杆的情况下,年化率增加到 41.0625%。 按照以上步骤,现货和永续合约交易市场的交易可以在任何提供的套利中进行。

1.6 风险分析

期货和现货套利的原理很简单。 很多交易者也会直接进行期货和现货套利,但行情瞬息万变,人工套利会隐藏以下风险:

2.获取币种的资金费率

我们使用 CCXT 框架。 对CCXT不熟悉的可以看我之前的文章,这里不再赘述。

2.1 OKEX

导入包

import json
import operator
import os
from tqdm import tqdm
import requests
import pandas as pd

# 代理proxy
os.environ["http_proxy"] = "http://127.0.0.1:21882"
os.environ["https_proxy"] = "http://127.0.0.1:21882"

# 连接交易所
exchange_id = "okx"
exchange_class = getattr(ccxt, exchange_id)
exchange = exchange_class({
    'apiKey': 'your api Key',
    'secret': 'your secret',
    'password': 'your password',
    'enableRateLimit': True
})
coin_rate = {}	

# 获取一个币种的资金费率
print(exchange.fetchFundingRate("BTC/USDT:USDT"))

在这里插入图片描述

# 这里没有ccxt提供的函数,我对照api手写了一个函数
# 获取币种的代码
def fetchSwapMarket():
    url = f"https://www.okex.com/api/v5/market/tickers?instType=SWAP"
    res = requests.get(url)
    json_res = json.loads(res.content)
    list_ = []
    if json_res["code"] == "0":
        for i in json_res["data"]:
            list_.append(i["instId"])
        return list_

def findMaxfee():
    swap_coin = fetchSwapMarket()
    print("正在寻找目标币种,请等待!")
    # 总进度
    total = len(swap_coin)
    with tqdm(total=total) as pbar:
        pbar.set_description('Processing:')
        for i, coin in enumerate(swap_coin):
            coin_rate[coin] = exchange.fetchFundingRate(coin)
            pbar.update(1)

在这里插入图片描述

可以看到XCH-USDT-SWAP在接下来的时间负资金率最高

3.买卖

核心:两笔交易行情相关、方向相反、数量相等、盈亏相等

MidClass中间类,封装了交易币种的相关信息

策略.py

class MidClass():
    # 初始化
    def __init__(self, ThisExchange, symbol):
        self.Exchange = ThisExchange
        self.Symbol = symbol
        market = ThisExchange.markets[self.Symbol]
        self.MinLeverage = market['limits']['leverage']['min']
        self.MaxLeverage = market['limits']['leverage']['max']
        self.Price_Precision = market['precision']['price']
        self.AmountPrecision = len(str(market['precision']['amount']).split(".")[-1])
        self.PricePrecision = len(str(market['precision']['price']).split(".")[-1])
        self.TakerFee = ThisExchange.markets[symbol]["taker"]
        self.MakerFee = ThisExchange.markets[symbol]["maker"]
        self.LimitAmount = market['limits']['amount']['min']
    # 获得交易对行情信息
    def GetTicker(self):
        self.High = '___'
        self.Low = '___'
        self.Buy = '___'
        self.Sell = '___'
        self.Last = '___'
        try:
            self.Ticker = self.Exchange.fetchTicker(self.Symbol)
            self.Time = self.Ticker["timestamp"]
            self.datetime = self.Ticker["datetime"]
            self.High = self.Ticker['high']
            self.Low = self.Ticker['low']
            self.Buy = self.Ticker['bid']
            self.Sell = self.Ticker['ask']
            self.Last = self.Ticker['last']
            return True  # 只要有一个成功就返回True
        except:
            return False  # 如果全都获取不了返回False
    @staticmethod
    def IsSpot(Symbol):
        if len(Symbol.split(':')) == 1:
            return True
        else:
            return False
    # 获得账户对于该交易对信息 只显示交易过的币种
    def GetAccount(self):
        self.Account = '___'
        self.Balance = '___'
        self.FrozenBalance = '___'
        self.Stocks = '___'
        self.FrozenStocks = '___'
        if MidClass.IsSpot(self.Symbol):
            self.SymbolStocksName = self.Symbol.split('/')[0]
            self.SymbolBalanceName = self.Symbol.split('/')[1]
        else:
            self.SymbolStocksName = self.Symbol.split(":")[0].split("/")[0]
            self.SymbolBalanceName = self.Symbol.split(":")[-1]
        try:
            self.Account = self.Exchange.fetchBalance()
            self.Balance = self.Account[self.SymbolBalanceName]['free']
            self.FrozenBalance = self.Account[self.SymbolBalanceName]['used']
            self.Stocks = self.Account[self.SymbolStocksName]['free']
            self.FrozenStocks = self.Account[self.SymbolStocksName]['used']
            return True
        except Exception as e:
            print("账户没有交易过这个币种!")
            return False
    # 确认是否获取到账户和交易对信息
    def RefreshData(self):
        if not self.GetAccount():
            return 'false get account'
        if not self.GetTicker():
            return 'false get ticker'
        return 'refresh data finish!'
    # 创建订单
    def CreateOrder(self, OrderType, Price, Amount):
        if round(Amount, self.AmountPrecision) < self.LimitAmount:
            raise RuntimeError("下单数量小于最小下单量,请加大保证金,或者提高杠杆!")
        if OrderType == 'buy':
            # 执行买单杠杆交易
            params = {
                "tdMode": "isolated",
            }
            OrderId = self.Exchange.create_order(self.Symbol, type="limit", side="buy",
                                                 amount=round(Amount, self.AmountPrecision),
                                                 price=round(Price, self.PricePrecision), params=params)["id"]
        elif OrderType == 'sell':
            # 执行卖单杠杆交易
            params = {
                "tdMode": "isolated",
            }
            OrderId = self.Exchange.create_order(self.Symbol, type="limit", side="sell",
                                                 amount=round(Amount, self.AmountPrecision),
                                                 price=round(Price, self.PricePrecision), params=params)["id"]
        elif OrderType == 'short':
            # 执行开空合约
            params = {
                "tdMode": "isolated",
                "posSide": "short"
            }
            OrderId = self.Exchange.create_order(self.Symbol, type="limit", side="sell",
                                                 amount=round(Amount, self.AmountPrecision),
                                                 price=round(Price, self.PricePrecision), params=params)["id"]
        elif OrderType == 'long':
            # 执行开多合约
            params = {
                "tdMode": "isolated",
                "posSide": "long"
            }
            OrderId = self.Exchange.create_order(self.Symbol, type="limit", side="buy",
                                                 amount=round(Amount, self.AmountPrecision),
                                                 price=round(Price, self.PricePrecision), params=params)["id"]
        else:
            pass
        self.GetAccount()
        return OrderId
    # 获取订单状态
    def GetOrder(self, Idd):
        self.OrderId = '___'
        self.OrderPrice = '___'
        self.OrderNum = '___'
        self.OrderDealNum = '___'
        self.OrderAvgPrice = '___'
        self.OrderStatus = '___'
        try:
            self.Order = self.Exchange.fetchOrder(Idd, self.Symbol)
            self.OrderId = self.Order['id']
            self.OrderPrice = self.Order['price']
            self.OrderNum = self.Order['amount']
            self.OrderDealNum = self.Order['filled']
            self.OrderAvgPrice = self.Order['average']
            self.OrderStatus = self.Order['status']
            return True
        except:
            return False
    # 取消订单
    def CancelOrder(self, Idd):
        self.CancelResult = '___'
        try:
            self.CancelResult = self.Exchange.cancelOrder(Idd, self.Symbol)
            return True
        except:
            return False
    # 获取k线数据
    def GetRecords(self, Timeframe='1m'):
        self.Records = '___'
        try:
            self.Records = self.Exchange.fetchOHLCV(self.Symbol, Timeframe)
            return True
        except:
            return False
    # 设置杠杆mgnMode:isolated/cross
    def SetLeverage(self, leverage, params=None):
        if MidClass.IsSpot(self.Symbol):
            if params is None:
                params = {"mgnMode": "isolated"}
        else:
            if params is None:
                params = {"mgnMode": "isolated", "posSide": "long"}
        try:
            if leverage <= self.MaxLeverage and leverage >= self.MinLeverage:
                self.LeverageInfo = self.Exchange.set_leverage(leverage, self.Symbol, params=params)
            return True
        except RuntimeError as e:
            print(e, "请注意杠杆倍数,不能超过交易所设定倍数!")
            return False

直到.py

def ShowInfo(MyMid):
    print("交易所时间:",MyMid.Time)
    print("交易所时间:",MyMid.datetime)
    print(MyMid.Symbol, '最新价:', MyMid.Last)
    print('该币种可用额度为:', round(MyMid.Stocks, 2), MyMid.SymbolStocksName)
    print('该币种冻结额度为:', round(MyMid.FrozenStocks, 2), MyMid.SymbolStocksName)
    print('账户可用额度为:', round(MyMid.Balance, 2), 'USDT')
    print('账户冻结额度为:', round(MyMid.FrozenBalance, 2), 'USDT')
    print('该币种taker手续费', MyMid.TakerFee)
    print('该币种Maker手续费', MyMid.MakerFee)
    print('-'*40)

运行条目

import os
import ccxt
from MMQT.MidClass import MidClass
from MMQT.Untils import *
# 代理proxy
os.environ["http_proxy"] = "http://127.0.0.1:21882"
os.environ["https_proxy"] = "http://127.0.0.1:21882"
# 连接交易所
exchange_id = "okx"
exchange_class = getattr(ccxt, exchange_id)
exchange = exchange_class({
    'apiKey': 'your apikey',
    'secret': 'your secret',
    'password': 'password',
    'enableRateLimit': True
})
if __name__ == '__main__':
    exchange.load_markets()
    # 中间模块实例化
    MyMid1 = MidClass(exchange, symbol="XCH/USDT:USDT")
    MyMid2 = MidClass(exchange, symbol="XCH/USDT")
    # # 数据更新
    MyMid1.RefreshData()
    MyMid2.RefreshData()
    # 显示相关数据
    ShowInfo(MyMid1)
    ShowInfo(MyMid2)
    # 设置杠杆
    leverage = 5
    MyMid1.SetLeverage(leverage)
    MyMid2.SetLeverage(leverage)
    # 设置资金
    totalMoney = MyMid1.Balance * leverage
    # # 开多合约
    price1 = (MyMid1.Buy+MyMid1.Sell)/2
    Amount = totalMoney*0.4 / (price1*MyMid1.Price_Precision)
    MyMid1.CreateOrder("long", price1, Amount)
    # 卖空现货
    price2 = (MyMid2.Buy + MyMid2.Sell) / 2
    Amount_ = totalMoney * 0.4 / MyMid2.Last
    MyMid2.CreateOrder("sell", price2, Amount_)

4.总结

人在币圈,怎能不湿鞋。 最后,我想强调一下这种策略的潜在风险:

资金利率波动风险

以上代码实现了选币、一键买卖、增加杠杆的功能。 但是目前还有很多潜力模块没有开发出来,直接操作实盘是绝对不可能的,存在很大的风险和漏洞。

本文仅供学习交流,不构成任何投资建议。

如果您觉得这篇文章对您有帮助,可以在离开前给作者点个赞!