Bienvenidos a compartir sus propias estrategias o mejorar el motor de repetición basado en este informe.
La segunda estrategia tiene un nuevo contenido de investigación, por lo que es recomendable consultar:https://www.fmz.com/digest-topic/5364
La política se ha publicado en versión de pago, con muchas mejoras, y está disponible para los comerciantes de Binance.
币安期货多币种对冲策略研究
币安期货最近发起了“千团大战”活动(活动地址:https://www.binance-cn.com/cn/futures/activity/tournament )。FMZ量化平台官方也组织了团队,直接搜索“FMZ”就可以找到,目前已经有200多人,欢迎参与,参加后可加下方微信,回复“币安”拉微信群。
<img src=“https://www.fmz.com/upload/asset/1fbed0c3795dbecac04.jpg” />
参与活动的用户均可获取此币安期货策略(策略源码将在活动前放出,也可以直接根据此报告自己的代码)。本篇即为此策略的研究报告。**注意策略只供参考,可以在此基础上提出自己的思路进行优化,也欢迎分享。**报告可直接在FMZ网站的研究环境直接使用(点击右上角下载,在研究环境中上传)。
研究环境点击控制中心,再点击箭头位置即可进入,打开上传的.pynb后缀的文件,按shift+enter逐行运行即可。研究环境的使用帮助里有基础的使用教程。 <img src=“https://www.fmz.com/upload/asset/1b39347a88aa4cff916.jpg” />
1.策略缘由
币安现货上架了许多山寨币,虽然短期涨跌不定,如果用日线观察久一些,就会发现基本都跌了90%以上,有的甚至只有最高价零头的零头。可是现货并没有普遍的做空手段,除了不碰山寨币,没有特别的建议。最近两月币安期货上线了二十多个永续合约,其中大多数时主流币种,也有一些默默无闻。这给了我们做空这些山寨币组合的手段。利用山寨币对于BTC往往下跌以及山寨币的走势相关系数很高,可以设计出两种策略。
2.策略原理
第一个策略:策略将分散等值做空选定的一篮子山寨币,同时等仓位做多比特币对冲,降低风险和波动率。随着价格的波动,不断调整仓位保持空头价值恒定和多头仓位对等。本质上时做空山寨币-比特币价格指数。
第二个策略:将做空价格高于山寨币-比特币价格指数的币种,做多低于指数的币种,偏离越大,仓位越大。同时将未对冲的头寸用BTC对冲(也可不对冲)。
# 需要导入的库 import pandas as pd import requests import matplotlib.pyplot as plt import seaborn as sns import numpy as np %matplotlib inline
3.筛选需要的币种
币安永续合约当前上架币种,用API获取,不包含BTC共23个。但研究环境不能访问外网,这里直接给出列表。
#Info = requests.get('https://fapi.binance.com/fapi/v1/exchangeInfo') #symbols = [symbol_info['baseAsset'] for symbol_info in Info.json()['symbols']] symbols = ['ETH', 'BCH', 'XRP', 'EOS', 'LTC', 'TRX', 'ETC', 'LINK', 'XLM', 'ADA', 'XMR', 'DASH', 'ZEC', 'XTZ', 'BNB', 'ATOM', 'ONT', 'IOTA', 'BAT', 'VET', 'NEO', 'QTUM', 'IOST']
首先我们研究一下过去一年山寨币对比特币的价格走势,数据我已经提前下载好,并传到了论坛上,可以在研究环境中直接引用
price_btc = pd.read_csv('https://www.fmz.com/upload/asset/1ef1af8ec28a75a2dcb.csv', index_col = 0) price_btc.index = pd.to_datetime(price_btc.index,unit='ms') #索引位日期
price_btc.tail()
ETH BCH XRP EOS LTC TRX \ 0 2020-03-21 0.021434 0.035580 0.000026 0.000368 0.006196 0.000002 2020-03-22 0.021026 0.034852 0.000025 0.000367 0.006086 0.000002 2020-03-23 0.021010 0.034186 0.000024 0.000353 0.006021 0.000002 2020-03-24 0.020529 0.033712 0.000024 0.000347 0.006012 0.000002 2020-03-25 0.020727 0.033480 0.000024 0.000348 0.005996 0.000002 ETC LINK XLM ADA ... XTZ BNB \ 0 ... 2020-03-21 0.000810 0.000367 0.000006 0.000005 ... 0.000268 0.001956 2020-03-22 0.000789 0.000341 0.000006 0.000005 ... 0.000253 0.001918 2020-03-23 0.000768 0.000348 0.000006 0.000005 ... 0.000259 0.001883 2020-03-24 0.000751 0.000343 0.000006 0.000004 ... 0.000261 0.001842 2020-03-25 0.000786 0.000339 0.000006 0.000004 ... 0.000258 0.001857 ATOM ONT IOTA BAT VET NEO \ 0 2020-03-21 0.000351 0.000060 0.000022 0.000022 4.700000e-07 0.001007 2020-03-22 0.000330 0.000059 0.000022 0.000021 4.400000e-07 0.001022 2020-03-23 0.000326 0.000058 0.000022 0.000021 4.400000e-07 0.001032 2020-03-24 0.000318 0.000057 0.000021 0.000023 4.500000e-07 0.001022 2020-03-25 0.000321 0.000056 0.000021 0.000023 4.600000e-07 0.001020 QTUM IOST 0 2020-03-21 0.000199 5.600000e-07 2020-03-22 0.000197 5.000000e-07 2020-03-23 0.000191 5.100000e-07 2020-03-24 0.000189 4.900000e-07 2020-03-25 0.000187 4.900000e-07 [5 rows x 23 columns]
先把这些币种价格画出来看看趋势,数据要归一化。可以看到除了四个币种外,其余币种的价格走势基本一致,呈现出下降趋势。
price_btc_norm = price_btc/price_btc.fillna(method='bfill').iloc[0,] price_btc_norm.plot(figsize=(16,6),grid = True,legend=False);
<Figure size 1152x432 with 1 Axes>
将最后价格变化排一下序,就可以找到明显不同的几个币,分别是LINK,XTZ,BCH, ETH。说明它们往往能走出独立行情,做空它们风险较高,需要排除策略之外。 将剩余的币种再画一个相关系数的热力图,发现ETC,ATOM的走势也相对特殊,可以排除。
price_btc_norm.iloc[-1,].sort_values()[-5:]
ETH 0.600417 ETC 0.661616 BCH 1.141961 XTZ 2.512195 LINK 2.764495 Name: 2020-03-25 00:00:00, dtype: float64
trade_symbols = list(set(symbols)-set(['LINK','XTZ','BCH', 'ETH'])) #剩余的币种
plt.subplots(figsize=(12, 12)) # 设置画面大小 sns.heatmap(price_btc[trade_symbols].corr(), annot=True, vmax=1, square=True, cmap="Blues");
<Figure size 864x864 with 2 Axes>
最后剩余的币种一年平均下跌66%,显然有充足的做空空间。把这些币的趋势合成出山寨币价格指数,发现基本一路下跌,去年下半年较稳定,今年又开始一路下跌。本此研究筛选出’LINK’,‘XTZ’,‘BCH’, ‘ETH’, ‘ETC’,‘ATOM’,‘BNB’,‘EOS’,'LTC’不参与第一个策略的做空,具体的币种可以自己回测。
需要注意的是,现在的山寨币指数处于过去一年中低点,也许不是做空良机,反而可以做多,需要根据个人选择。
trade_symbols = list(set(symbols)-set(['LINK','XTZ','BCH', 'ETH', 'ETC','ATOM','BNB','EOS','LTC'])) #剩余的币种,具体减去哪些,可自己设定。 1-price_btc_norm[trade_symbols].iloc[-1,].mean()
0.6714306758250285
price_btc_norm[trade_symbols].mean(axis=1).plot(figsize=(16,6),grid = True,legend=False);
<Figure size 1152x432 with 1 Axes>
4.币安永续数据
同样的,币安永续的数据已经整理好了,你也可以在自己的notebook中直接引用,数据是2020年1月28到3月31日的1h行情K线,因为币安上线大部分永续合约的时间就这两个月,所以数据用于回测是够了。
price_usdt = pd.read_csv('https://www.fmz.com/upload/asset/20227de6c1d10cb9dd1.csv ', index_col = 0) price_usdt.index = pd.to_datetime(price_usdt.index)
price_usdt.tail()
BTC ETH BCH XRP EOS LTC TRX \ 0 2020-04-07 23:00:00 7192.90 164.55 252.51 0.1925 2.632 44.83 0.01329 2020-04-08 00:00:00 7153.32 164.42 251.62 0.1914 2.591 44.41 0.01321 2020-04-08 01:00:00 7160.02 163.83 250.55 0.1924 2.601 44.53 0.01321 2020-04-08 02:00:00 7262.37 168.74 264.67 0.1972 2.684 45.94 0.01352 2020-04-08 03:00:00 7378.88 172.81 275.81 0.2003 2.741 46.68 0.01371 ETC LINK XLM ... XTZ BNB ATOM ONT \ 0 ... 2020-04-07 23:00:00 5.475 2.729 0.04843 ... 1.960 14.725 2.346 0.4219 2020-04-08 00:00:00 5.415 2.719 0.04816 ... 1.928 14.588 2.321 0.4167 2020-04-08 01:00:00 5.428 2.758 0.04818 ... 1.943 14.592 2.320 0.4152 2020-04-08 02:00:00 5.586 2.808 0.04947 ... 1.995 14.902 2.378 0.4244 2020-04-08 03:00:00 5.720 2.838 0.05033 ... 2.052 15.339 2.419 0.4355 IOTA BAT VET NEO QTUM IOST 0 2020-04-07 23:00:00 0.1632 0.1611 0.003873 7.719 1.373 0.003394 2020-04-08 00:00:00 0.1628 0.1600 0.003822 7.658 1.366 0.003368 2020-04-08 01:00:00 0.1628 0.1633 0.003815 7.657 1.369 0.003373 2020-04-08 02:00:00 0.1662 0.1674 0.003873 7.800 1.400 0.003442 2020-04-08 03:00:00 0.1700 0.1702 0.003930 7.965 1.420 0.003484 [5 rows x 24 columns]
先归一化数据看一下整体走势,在3月份的大跌中,相对于2月初的价格,普遍腰斩,可见永续的风险也很高,这波大跌也是对策略的考验。
price_usdt_norm = price_usdt/price_usdt.fillna(method='bfill').iloc[0,] price_usdt_norm.plot(figsize=(16,6),grid = True,legend=False);
<Figure size 1152x432 with 1 Axes>
将我们要做空的币相对于比特币的指数价格画出来,策略原理就是做空这条曲线,收益也基本上是这条曲线反过来。
price_usdt_btc = price_usdt.divide(price_usdt['BTC'],axis=0) price_usdt_btc_norm = price_usdt_btc/price_usdt_btc.fillna(method='bfill').iloc[0,] price_usdt_btc_norm[trade_symbols].mean(axis=1).plot(figsize=(16,6),grid = True); #price_usdt_btc_norm.mean(axis=1).plot(figsize=(16,6),grid = True,legend=False);
<Figure size 1152x432 with 1 Axes>
5.回测引擎
由于FMZ本地回测并没有所有币种的数据,也不支持多币种回测,所以需要重新实现一个回测引擎,写的比较简单,但也基本够用。考虑到了手续费,但基本忽略了资金费率,没有考虑维持保证金的情况。记录了总权益、占用保证金、杠杆等历史。由于这次策略基本多空对等的,所以资金费率的影响不大。
回测并未考虑到滑价情况,可以自行加大手续费模拟,考虑到币安maker手续费低,即使是冷门币种的盘口差价也很小,实际下单中可以利用冰山委托的方式下单,影响应该不大。
创建交易所对象时,需要指定要交易的币种,Buy做多,Sell做空,由于永续的限制,同时多空会自动平仓, 当做空时币种数量为负。参数如下:
class Exchange: def __init__(self, trade_symbols, leverage=20, commission=0.00005, initial_balance=10000, log=False): self.initial_balance = initial_balance #初始的资产 self.commission = commission self.leverage = leverage self.trade_symbols = trade_symbols self.date = '' self.log = log self.df = pd.DataFrame(columns=['margin','total','leverage','realised_profit','unrealised_profit']) self.account = {'USDT':{'realised_profit':0, 'margin':0, 'unrealised_profit':0, 'total':initial_balance, 'leverage':0}} for symbol in trade_symbols: self.account[symbol] = {'amount':0, 'hold_price':0, 'value':0, 'price':0, 'realised_profit':0, 'margin':0, 'unrealised_profit':0} def Trade(self, symbol, direction, price, amount, msg=''): if self.date and self.log: print('%-20s%-5s%-5s%-10.8s%-8.6s %s'%(str(self.date), symbol, 'buy' if direction == 1 else 'sell', price, amount, msg)) cover_amount = 0 if direction*self.account[symbol]['amount'] >=0 else min(abs(self.account[symbol]['amount']), amount) open_amount = amount - cover_amount self.account['USDT']['realised_profit'] -= price*amount*self.commission #扣除手续费 if cover_amount > 0: #先平仓 self.account['USDT']['realised_profit'] += -direction*(price - self.account[symbol]['hold_price'])*cover_amount #利润 self.account['USDT']['margin'] -= cover_amount*self.account[symbol]['hold_price']/self.leverage #释放保证金 self.account[symbol]['realised_profit'] += -direction*(price - self.account[symbol]['hold_price'])*cover_amount self.account[symbol]['amount'] -= -direction*cover_amount self.account[symbol]['margin'] -= cover_amount*self.account[symbol]['hold_price']/self.leverage self.account[symbol]['hold_price'] = 0 if self.account[symbol]['amount'] == 0 else self.account[symbol]['hold_price'] if open_amount > 0: total_cost = self.account[symbol]['hold_price']*direction*self.account[symbol]['amount'] + price*open_amount total_amount = direction*self.account[symbol]['amount']+open_amount self.account['USDT']['margin'] += open_amount*price/self.leverage self.account[symbol]['hold_price'] = total_cost/total_amount self.account[symbol]['amount'] += direction*open_amount self.account[symbol]['margin'] += open_amount*price/self.leverage self.account[symbol]['unrealised_profit'] = (price - self.account[symbol]['hold_price'])*self.account[symbol]['amount'] self.account[symbol]['price'] = price self.account[symbol]['value'] = abs(self.account[symbol]['amount'])*price return True def Buy(self, symbol, price, amount, msg=''): self.Trade(symbol, 1, price, amount, msg) def Sell(self, symbol, price, amount, msg=''): self.Trade(symbol, -1, price, amount, msg) def Update(self, date, close_price): #对资产进行更新 self.date = date self.close = close_price self.account['USDT']['unrealised_profit'] = 0 for symbol in self.trade_symbols: if np.isnan(close_price[symbol]): continue self.account[symbol]['unrealised_profit'] = (close_price[symbol] - self.account[symbol]['hold_price'])*self.account[symbol]['amount'] self.account[symbol]['price'] = close_price[symbol] self.account[symbol]['value'] = abs(self.account[symbol]['amount'])*close_price[symbol] self.account['USDT']['unrealised_profit'] += self.account[symbol]['unrealised_profit'] if self.date.hour in [0,8,16]: pass self.account['USDT']['realised_profit'] += -self.account[symbol]['amount']*close_price[symbol]*0.01/100 self.account['USDT']['total'] = round(self.account['USDT']['realised_profit'] + self.initial_balance + self.account['USDT']['unrealised_profit'],6) self.account['USDT']['leverage'] = round(self.account['USDT']['margin']/self.account['USDT']['total'],4)*self.leverage self.df.loc[self.date] = [self.account['USDT']['margin'],self.account['USDT']['total'],self.account['USDT']['leverage'],self.account['USDT']['realised_profit'],self.account['USDT']['unrealised_profit']]
# 先测试一下回测引擎 e = Exchange(['BTC','XRP'],initial_balance=10000,commission=0,log=True) e.Buy('BTC',100, 5) e.Sell('XRP',10, 50) e.Sell('BTC',105,e.account['BTC']['amount']) e.Buy('XRP',9,-e.account['XRP']['amount']) round(e.account['USDT']['realised_profit'],4)
75.0
6.第一个策略代码
策略逻辑:
做空的价值trade_value,决定了仓位的大小。设置log=True将打印交易日志
# 需要与BTC对冲 trade_symbols = list(set(symbols)-set(['LINK','XTZ','BCH', 'ETH', 'ETC','ATOM','BNB','EOS','LTC'])) #剩余的币种 e = Exchange(trade_symbols+['BTC'],initial_balance=10000,commission=0.0005,log=False) trade_value = 2000 for row in price_usdt.iloc[:].iterrows(): e.Update(row[0], row[1]) empty_value = 0 for symbol in trade_symbols: price = row[1][symbol] if np.isnan(price): continue if e.account[symbol]['value'] - trade_value < -20 : e.Sell(symbol, price, round((trade_value-e.account[symbol]['value'])/price, 6),round(e.account[symbol]['realised_profit']+e.account[symbol]['unrealised_profit'],2)) if e.account[symbol]['value'] - trade_value > 20 : e.Buy(symbol, price, round((e.account[symbol]['value']-trade_value)/price, 6),round(e.account[symbol]['realised_profit']+e.account[symbol]['unrealised_profit'],2)) empty_value += e.account[symbol]['value'] price = row[1]['BTC'] if e.account['BTC']['value'] - empty_value < -20: e.Buy('BTC', price, round((empty_value-e.account['BTC']['value'])/price,6),round(e.account['BTC']['realised_profit']+e.account['BTC']['unrealised_profit'],2)) if e.account['BTC']['value'] - empty_value > 20: e.Sell('BTC', price, round((e.account['BTC']['value']-empty_value)/price,6),round(e.account['BTC']['realised_profit']+e.account['BTC']['unrealised_profit'],2)) stragey_1 = e
最终各个币种的利润如下:
pd.DataFrame(stragey_1.account).T.apply(lambda x:round(x,3))
realised_profit margin unrealised_profit total leverage \ USDT 5576.449 2350.526 -536.669 15057.009 3.176 DASH 847.374 86.354 -272.925 NaN NaN IOST 926.829 88.409 -231.819 NaN NaN ONT 1302.690 85.751 -284.984 NaN NaN XMR 654.856 77.073 -458.549 NaN NaN XLM 643.571 81.016 -379.678 NaN NaN IOTA 1358.780 82.337 -353.258 NaN NaN QTUM 902.930 87.172 -256.569 NaN NaN BAT 1013.011 82.470 -350.592 NaN NaN XRP 682.601 83.889 -322.224 NaN NaN VET 1278.532 78.069 -438.614 NaN NaN NEO 1109.221 83.870 -322.590 NaN NaN ADA 982.309 81.397 -372.060 NaN NaN ZEC 1173.761 82.286 -354.278 NaN NaN TRX 706.935 82.172 -356.555 NaN NaN BTC -7708.165 1188.261 4234.779 NaN NaN amount hold_price value price USDT NaN NaN NaN NaN DASH -26.788 64.472 2000.000 74.660 IOST -574052.813 0.003 2000.000 0.003 ONT -4592.423 0.373 2000.000 0.436 XMR -34.471 44.717 2000.000 58.020 XLM -39737.731 0.041 2000.000 0.050 IOTA -11764.706 0.140 2000.000 0.170 QTUM -1408.451 1.238 2000.000 1.420 BAT -11750.881 0.140 2000.000 0.170 XRP -9985.022 0.168 2000.000 0.200 VET -508905.852 0.003 2000.000 0.004 NEO -251.099 6.680 2000.000 7.965 ADA -54510.766 0.030 2000.000 0.037 ZEC -52.618 31.277 2000.000 38.010 TRX -145878.920 0.011 2000.000 0.014 BTC 3.795 6262.883 28000.001 7378.880
下面两幅图分别是净值曲线和使用的杠杆。
净值曲线中黄色的是1倍杠杆做空山寨币指数的效果,可以看到策略基本放大了指数的波动,符合预期。最终两个月收益60%,最大回撤20%,最大使用杠杆约8倍,大部分时间都在6倍以下,还是比较安全的。最重要的是,完全对冲使得策略在3月12号大跌中损失不大。
当做空的币价上涨,合约价值增加,此时是减仓的,反之盈利是加仓。这使得总的合约价值维持恒定,即使暴涨暴跌也损失有限。
但风险前面也提到了,山寨币是很有可能走出独立的行情的,并且有可能从底部抬升不少。这取决与如何使用,如果你看好山寨币并认为已经到底部,可以方向操作,做多指数。或者你看好某几个币种,可以和它们对冲。
(stragey_1.df['total']/stragey_1.initial_balance).plot(figsize=(18,6),grid = True);#净值曲线 #(2-price_usdt_btc_norm[trade_symbols].mean(axis=1)).plot(figsize=(18,6),grid = True);
<Figure size 1296x432 with 1 Axes>
# 策略的杠杆 stragey_1.df['leverage'].plot(figsize=(18,6),grid = True);
<Figure size 1296x432 with 1 Axes>
当然由于山寨币对USDT的价格也是下跌的,极端的方案是不对冲,直接裸空,但波动很大,回撤很高
trade_symbols = list(set(symbols)-set(['LINK','XTZ','BCH', 'ETH', 'ETC','ATOM','BNB','EOS','LTC'])) #剩余的币种 e = Exchange(trade_symbols+['BTC'],initial_balance=10000,commission=0.0005,log=False) trade_value = 2000 for row in price_usdt.iloc[:].iterrows(): e.Update(row[0], row[1]) empty_value = 0 for symbol in trade_symbols: price = row[1][symbol] if np.isnan(price): continue if e.account[symbol]['value'] - trade_value < -20 : e.Sell(symbol, price, round((trade_value-e.account[symbol]['value'])/price, 6),round(e.account[symbol]['realised_profit']+e.account[symbol]['unrealised_profit'],2)) if e.account[symbol]['value'] - trade_value > 20 : pass #e.Buy(symbol, price, round((e.account[symbol]['value']-trade_value)/price, 6),round(e.account[symbol]['realised_profit']+e.account[symbol]['unrealised_profit'],2)) empty_value += e.account[symbol]['value'] stragey_1b = e
(stragey_1b.df['total']/stragey_1.initial_balance).plot(figsize=(18,6),grid = True);#净值曲线 (2-price_usdt_btc_norm[trade_symbols].mean(axis=1)).plot(figsize=(18,6),grid = True);
<Figure size 1296x432 with 1 Axes>
7.第二个策略代码
策略逻辑:
同样由trade_value控制开仓大小。也可以修改diff/0.001的换算系数
trade_symbols = list(set(symbols)-set(['LINK','XTZ','BCH', 'ETH'])) #剩余的币种 price_usdt_btc_norm_mean = price_usdt_btc_norm[trade_symbols].mean(axis=1) e = Exchange(trade_symbols+['BTC'],initial_balance=10000,commission=0.0005,log=False) trade_value = 300 for row in price_usdt.iloc[:].iterrows(): e.Update(row[0], row[1]) empty_value = 0 for symbol in trade_symbols: price = row[1][symbol] if np.isnan(price): continue diff = price_usdt_btc_norm.loc[row[0],symbol] - price_usdt_btc_norm_mean[row[0]] aim_value = -trade_value*round(diff/0.01,0) now_value = e.account[symbol]['value']*np.sign(e.account[symbol]['amount']) empty_value += now_value if aim_value - now_value > 50: e.Buy(symbol, price, round((aim_value - now_value)/price, 6),round(e.account[symbol]['realised_profit']+e.account[symbol]['unrealised_profit'],2)) if aim_value - now_value < -50: e.Sell(symbol, price, -round((aim_value - now_value)/price, 6),round(e.account[symbol]['realised_profit']+e.account[symbol]['unrealised_profit'],2)) price = row[1]['BTC'] aim_value = -empty_value now_value = e.account['BTC']['value']*np.sign(e.account['BTC']['amount']) if aim_value - now_value > 50: e.Buy('BTC', price, round((aim_value - now_value)/price, 6),round(e.account['BTC']['realised_profit']+e.account['BTC']['unrealised_profit'],2)) if aim_value - now_value < -50: e.Sell('BTC', price, -round((aim_value - now_value)/price, 6),round(e.account['BTC']['realised_profit']+e.account['BTC']['unrealised_profit'],2)) stragey_2 = e
策略的收益相对第一个策略好上不少,近两个月有100%的收益,但还是有20%的回撤,并且最近一周由于行情波动较小,收益不明显。总体的杠杆也不多。这个策略值得尝试。根据偏离程度的不同,最多的开了7800多USDT。
注意到如果某个币走出了独立的行情,比如相对于指数上涨了几倍,将会在该币种上积累大量的做空仓位,同样的大幅下跌也会使得策略大量做多,可以限制最大开仓价值。
(stragey_2.df['total']/stragey_2.initial_balance).plot(figsize=(18,6),grid = True);
<Figure size 1296x432 with 1 Axes>
# 各币种汇总结果 pd.DataFrame(e.account).T.apply(lambda x:round(x,3))
realised_profit margin unrealised_profit total leverage \ USDT 11544.446 2240.648 -572.088 20961.347 2.142 LTC 208.435 71.269 -74.615 NaN NaN DASH -1611.443 15.000 -0.000 NaN NaN IOTA -731.880 137.227 255.450 NaN NaN QTUM 3695.002 15.000 8.472 NaN NaN EOS 515.414 15.000 -16.148 NaN NaN XRP 804.351 213.625 -527.496 NaN NaN VET 2029.654 119.771 39.893 NaN NaN NEO 1046.044 44.474 39.211 NaN NaN ADA 606.302 29.077 -26.916 NaN NaN BNB 895.348 71.510 -69.793 NaN NaN TRX 980.596 141.199 -218.180 NaN NaN IOST 3369.938 103.764 24.726 NaN NaN ETC -2929.940 245.720 485.595 NaN NaN ONT 1365.283 216.755 464.890 NaN NaN XMR 662.873 239.586 -608.286 NaN NaN XLM 319.303 238.507 -629.853 NaN NaN ATOM 1501.062 113.670 126.604 NaN NaN BAT 1572.965 45.429 -29.451 NaN NaN ZEC -1108.730 126.443 171.133 NaN NaN BTC 164.300 37.620 -0.000 NaN NaN amount hold_price value price USDT NaN NaN NaN NaN LTC -32.134 44.358 1500.000 46.680 DASH -4.018 74.660 300.000 74.660 IOTA 17647.059 0.156 3000.000 0.170 QTUM 217.234 1.381 308.472 1.420 EOS -115.340 2.601 316.148 2.741 XRP -23964.054 0.178 4800.000 0.200 VET 619674.671 0.004 2435.321 0.004 NEO 116.595 7.629 928.682 7.965 ADA -16583.748 0.035 608.458 0.037 BNB -97.790 14.625 1500.000 15.339 TRX -221893.491 0.013 3042.160 0.014 IOST 602755.454 0.003 2100.000 0.003 ETC 944.056 5.206 5400.000 5.720 ONT 11021.814 0.393 4800.000 0.436 XMR -93.071 51.484 5400.000 58.020 XLM -107291.874 0.044 5400.000 0.050 ATOM 992.146 2.291 2400.000 2.419 BAT -5511.329 0.165 938.028 0.170 ZEC 71.034 35.601 2700.000 38.010 BTC -0.102 7378.880 752.395 7378.880
e.df['leverage'].plot(figsize=(18,6),grid = True);
<Figure size 1296x432 with 1 Axes>
如果不对冲的结果如下,实际上差别不大。因为多空基本是平衡的。
trade_symbols = list(set(symbols)-set(['LINK','XTZ','BCH', 'ETH']))#剩余的币种 price_usdt_btc_norm_mean = price_usdt_btc_norm[trade_symbols].mean(axis=1) e = Exchange(trade_symbols,initial_balance=10000,commission=0.0005,log=False) trade_value = 300 for row in price_usdt.iloc[:].iterrows(): e.Update(row[0], row[1]) empty_value = 0 for symbol in trade_symbols: price = row[1][symbol] if np.isnan(price): continue diff = price_usdt_btc_norm.loc[row[0],symbol] - price_usdt_btc_norm_mean[row[0]] aim_value = -trade_value*round(diff/0.01,1) now_value = e.account[symbol]['value']*np.sign(e.account[symbol]['amount']) empty_value += now_value if aim_value - now_value > 20: e.Buy(symbol, price, round((aim_value - now_value)/price, 6),round(e.account[symbol]['realised_profit']+e.account[symbol]['unrealised_profit'],2)) if aim_value - now_value < -20: e.Sell(symbol, price, -round((aim_value - now_value)/price, 6),round(e.account[symbol]['realised_profit']+e.account[symbol]['unrealised_profit'],2)) stragey_2b = e
(stragey_2b.df['total']/stragey_2.initial_balance).plot(figsize=(18,6),grid = True); #(stragey_2.df['total']/stragey_2.initial_balance).plot(figsize=(18,6),grid = True); #可叠加在一起看看
<Figure size 1296x432 with 1 Axes>
如果参考USDT的价格回归,效果会差很多
trade_symbols = list(set(symbols)-set(['LINK','XTZ','BCH', 'ETH']))+['BTC'] #剩余的币种 price_usdt_norm_mean = price_usdt_norm[trade_symbols].mean(axis=1) e = Exchange(trade_symbols,initial_balance=10000,commission=0.0005,log=False) trade_value = 300 for row in price_usdt.iloc[:].iterrows(): e.Update(row[0], row[1]) empty_value = 0 for symbol in trade_symbols+['BTC']: price = row[1][symbol] if np.isnan(price): continue diff = price_usdt_norm.loc[row[0],symbol] - price_usdt_norm_mean[row[0]] aim_value = -trade_value*round(diff/0.01,1) now_value = e.account[symbol]['value']*np.sign(e.account[symbol]['amount']) empty_value += now_value if aim_value - now_value > 20: e.Buy(symbol, price, round((aim_value - now_value)/price, 6),round(e.account[symbol]['realised_profit']+e.account[symbol]['unrealised_profit'],2)) if aim_value - now_value < -20: e.Sell(symbol, price, -round((aim_value - now_value)/price, 6),round(e.account[symbol]['realised_profit']+e.account[symbol]['unrealised_profit'],2)) stragey_2c = e
(stragey_2c.df['total']/stragey_2.initial_balance).plot(figsize=(18,6),grid = True); (stragey_2b.df['total']/stragey_2.initial_balance).plot(figsize=(18,6),grid = True);
<Figure size 1296x432 with 1 Axes>
如果限制最大持仓价值,表现会差一些
trade_symbols = list(set(symbols)-set(['LINK','XTZ','BCH', 'ETH'])) #剩余的币种 price_usdt_btc_norm_mean = price_usdt_btc_norm[trade_symbols].mean(axis=1) e = Exchange(trade_symbols+['BTC'],initial_balance=10000,commission=0.0005,log=False) trade_value = 300 for row in price_usdt.iloc[:].iterrows(): e.Update(row[0], row[1]) empty_value = 0 for symbol in trade_symbols: price = row[1][symbol] if np.isnan(price): continue diff = price_usdt_btc_norm.loc[row[0],symbol] - price_usdt_btc_norm_mean[row[0]] aim_value = -trade_value*round(diff/0.01,1) now_value = e.account[symbol]['value']*np.sign(e.account[symbol]['amount']) empty_value += now_value if aim_value - now_value > 20 and abs(aim_value)<3000: e.Buy(symbol, price, round((aim_value - now_value)/price, 6),round(e.account[symbol]['realised_profit']+e.account[symbol]['unrealised_profit'],2)) if aim_value - now_value < -20 and abs(aim_value)<3000: e.Sell(symbol, price, -round((aim_value - now_value)/price, 6),round(e.account[symbol]['realised_profit']+e.account[symbol]['unrealised_profit'],2)) price = row[1]['BTC'] aim_value = -empty_value now_value = e.account['BTC']['value']*np.sign(e.account['BTC']['amount']) if aim_value - now_value > 20: e.Buy('BTC', price, round((aim_value - now_value)/price, 6),round(e.account['BTC']['realised_profit']+e.account['BTC']['unrealised_profit'],2)) if aim_value - now_value < -20: e.Sell('BTC', price, -round((aim_value - now_value)/price, 6),round(e.account['BTC']['realised_profit']+e.account['BTC']['unrealised_profit'],2)) stragey_2d = e
(stragey_2d.df['total']/stragey_2.initial_balance).plot(figsize=(17,6),grid = True);
<Figure size 1224x432 with 1 Axes>
8.总结与风险
第一个策略利用了山寨币总体价值不如比特币的特点,如果你看多比特币,不妨将这个策略长期坚持用下去,由于多空对等,也基本不怕8h一次的资金费率。长期来看,胜率比较高。但也担心山寨币目前在底部,有可能走出一段上涨的行情,造成策略的亏损。
第二个策略运用了山寨币的价格回归特性,涨的比指数多,大概率要跌回来。但可能会在单币种累计过多仓位,如果某个币真的一飞冲天不回头,会产生较大亏损。
由于策略的启动时间不同,具体参数不同,使用这个策略的人比较多时影响应该也不是很大。
总之,没有完美的策略,只有正确看待策略的态度,它终究还取决与使用者对风险的理解和对未来的判断。
这两个策略将在比赛前放出FMZ发明者量化平台的源码供大家参考。再此之前,也可以自己写出来,欢迎大家分享。
Las hierbasLos Estados miembros deberán establecer un marco para la evaluación de los riesgos de los sistemas de gestión de riesgos y de los sistemas de gestión de riesgos.
Las hierbas/cargar/activo/20c6b6d8de91f682f97.png
Las hierbasLos datos de los datos de los Estados miembros sobre las operaciones de los bancos centrales y de los bancos centrales de los Estados miembros se publican en el Diario Oficial de la Unión Europea.
Las hierbas/cargar/activo/1420b2081ecd122522d.csv
excmParece que los huevos no sirven de nada para determinar por qué los osos deben estar cubiertos.
Las hierbasLa política se basó en los comentarios de los usuarios, modificando algunos códigos y instrucciones de la política, copiando el código directamente con Ctrl + A, guardando el código cubierto, reiniciando el robot para usar el código más reciente. En la actualidad, la mayoría de los usuarios de fmz están conectados a la red. En la actualidad, la mayoría de las personas que viven en la ciudad de Nueva York son mujeres.
Las hierbasLas estrategias concretas se han hecho públicas en la plaza.
Las hierbas/upload/asset/20227de6c1d10cb9dd1.csv última hora línea K
Bloqueo del icebergEsperando el código fuente
el fuego del cieloEs muy bueno.
¿Qué quieres decir?Qué bueno.