在数字货币量化领域的资料实在是太少了,我总结了一下我的经验(以火币交易所为例)以供小白参考
第一步:申请api key和secret,
第二步:查看交易所的api文档(https://huobiapi.github.io/docs/spot/v1/cn/#185368440e)
第三步:这里其实是困扰很多小白的一部,就是拿到了api不知道该怎么用,首先火币提供了不同语言版本的sdk,可以利用这些sdk中提供的方法来查询历史k线,盘口情况,实时价格以及常用的各种信息,当然也可以选择一些封装好的第三方库比如ccxt,来实现上述数据的获取。一般来说ccxt这种库会对数据格式进行进一步处理,使用起来方便,而火币原生的sdk只是提供方法,后面的数据处理得自己实现,就比如原生sdk获取的历史k线是按时间降序排序的,你计算ma的时候还要自己重新排序,但如果想要实现一个量化系统的话还是建议使用sdk好一点,自己写轮子方便调用
第四步:就是把自己的交易逻辑用代码实现,比如使用双均线策略,
huobipro = ccxt.huobipro({ 'apiKey': '', 'secret': '', })
先使用ccxt获取交易所的实例,然后获取历史k线,得到的数据使用dataframe格式接受
huobipro.fetch_ohlcv(symbol=symbol, limit=limit_num, timeframe=timeframe)
然后利用pandas提供的函数计算MA,
df['median_short'] = df['close'].rolling(n_short, min_periods=1).mean()
df['median_long'] = df['close'].rolling(n_long, min_periods=1).mean()
然后再找出买入卖出信号,
# 找出买入信号 condition1 = df['median_short'] > df['median_long'] # 短均线上穿长均线 condition2 = df['median_short'].shift(1) <= df['median_long'].shift(1) df.loc[condition1 & condition2, 'signal'] = 1 # 产生买入信号的k线标记为1 # 找出卖出信号 condition1 = df['median_short'] < df['median_long'] # 短均线上穿长均线 condition2 = df['median_short'].shift(1) >= df['median_long'].shift(1) df.loc[condition1 & condition2, 'signal'] = 0 # 产生卖出信号的k线标记为0
有了交易信号,就可以获取信号,再判断进行下单(huobipro.create_limit_buy/sell_order()了)
第五步:其实第四步就可以交易了,第五步是回测,一般来说先回测再根据回测结果选用策略,最后才进行实盘
回测分析的相关有很多种,在这方面我也不是很懂,目前我还是习惯用累计利润来进行分析,
# 由signal计算出实际的每天持仓 df['pos'] = df['signal'].shift() df['pos'].fillna(method='ffill', inplace=True) df['pos'].fillna(value=0, inplace=True)
到这里持仓信号就有了,就可以根据持仓和历史k线的价格计算累计利润了,
df['change'] = df['close'].pct_change(1) # 根据收盘价计算涨跌幅 df['by_at_open_change'] = df['close'] / df['open'] - 1 # 开盘买入到收盘的涨跌幅 df['sell_next_open_change'] = df['open'].shift(-1) / df['close'] - 1 # 这根收盘到下根开盘的涨跌幅 df.at[len(df) - 1, 'sell_next_open_change'] = 0 # 补全空值 df.at[4, 'B'] # 选取开仓条件 condition1 = df['pos'] == 1 condition2 = df['pos'] != df['pos'].shift(1) open_pos_condition = condition1 & condition2 # 选取平仓条件 condition1 = df['pos'] == 0 condition2 = df['pos'] != df['pos'].shift(1) close_pos_condition = condition1 & condition2 # 对每次交易进行分组 df.loc[open_pos_condition, 'start_time'] = df['open_time'] df['start_time'].fillna(method='ffill', inplace=True) df.loc[df['pos'] == 0, 'start_time'] = pd.NaT init_cash = 1000 # 初始资金 # 计算仓位变动 # 开仓时仓位 df.loc[open_pos_condition, 'position'] = init_cash * (1 + df['by_at_open_change']) group_num = len(df.groupby('start_time')) if group_num > 1: temp = df.groupby('start_time').apply(lambda x: x['close'] / x.iloc[0]['close'] * x.iloc[0]['position']) temp = temp.reset_index(level=[0]) df['position'] = temp['close'] df['position_max'] = df['position'] * df['high'] / df['close'] df['position_min'] = df['position'] * df['low'] / df['close'] # #平仓时的仓位 # df.loc[close_pos_condition,'position']*=(1+df.loc[close_pos_condition,'sell_next_open_change']) # 计算持仓利润 df['porfit'] = (df['position'] - init_cash) * df['pos'] # 持仓利润或亏损 # df.loc[df['pos']==1,'porfit_min']=(df['position_min']-init_cash)*df['pos'] #最小持仓盈利或亏损 # df.loc[df['pos']==0,'porfit_max']=(df['position_max']-init_cash)*df['pos'] # 计算实际资金量 df['cash'] = init_cash + df['porfit'] # 实际资金 # 计算资金曲线 df['equity_change'] = df['cash'].pct_change() # 开仓日收益率 df.loc[open_pos_condition, 'equity_change'] = df.loc[open_pos_condition, 'cash'] / init_cash - 1 df['equity_change'].fillna(value=0, inplace=True) df['equity_curve'] = (1 + df['equity_change']).cumprod() df['equity_curve'] = df['equity_curve'] * init_cash
从回测结果来看,双均线策略比较吃单边行情,震荡行情的话基本就是送手续费,而且比较适合大周期,日线级别啥的,不适合高频交易,以bsv为例,bsv是回测结果比较好的
实际走势:
以投入1000u为例,不考虑手续费的情况下,每天的资金情况如回测结果所示,最小640,最大10521,十倍,基本算是约等于bsv的最大涨幅,但还有很多小波段没吃到,而且周期算是比较长的,btc回测也有3倍左右,最惨的是山寨,基本都是亏损
嗯,先写这么多,后面有想法了再更,可能是可视化回测方面的
可以看到其自上线最低价为49.17,最高价为455.55,最大涨幅为9.26倍.如果2018年12月6号91买入,现价192.5,持仓到现在利润约为2.11倍,而该系统的收益为8.43倍.也就是说该系统的双均线策略远远领先不操作的收益.但是也应该看到该币种最大涨幅为9.26倍,该策略尚未领先其最大涨幅,
可以看到其自上线最低价为49.17,最高价为455.55,最大涨幅为9.26倍.如果2018年12月6号91买入,现价192.5,持仓到现在利润约为2.11倍,而该系统的收益为8.43倍.也就是说该系统的双均线策略远远领先不操作的收益.但是也应该看到该币种最大涨幅为9.26倍,该策略尚未领先其最大涨幅,