Python數字貨幣量化交易開發——構建回測功能
前言
上次建立了一個簡易的csv資料庫,在執行了大概一週左右的時間裡積累了一定量的資料已經可以用於除錯回測系統了,所以這篇部落格主要記錄一下回測系統的建立,再次強調並非程式設計師,所以很多東西都是想當然的,不吝指正。
_
_
Episode 2. 構建回測功能
構建一個回測邏輯,主要分為以下四塊:
1、初始化部分,讀取之前一直在更新的csv價格庫並轉換為所需要的資料格式,系統的需求主要是知道目前的回測位置、時間戳和價格,所以初步構想的資料結構如下:
'''
step_value:回測進度的位置,直接用1到資料總長的順序數字排序來定義
對應的.value就是交易所的ohlcv資料加上.key方便之後呼叫
'''
{step_value:{'time':value1,'open':value2,'high':value3,'low':value4,'close':value5,'volume':value6}}
2、封裝功能部分,在做回測時需要呼叫的各種用於資料重新整理的class rerun(),包括更新賬戶餘額、更新每一步回測最新價格、處理買賣請求、處理在某個時間點交易邏輯發來的過往資料請求等等。
3、交易邏輯,呼叫已封裝好的功能做出交易判斷的部分。
4、回測邏輯,在每一個step_value上重複一次交易邏輯。
話不多說開始碼python:
'''
初始化呼叫csv部分
'''
symbol='ETH/USDT'
ini_account_dict={'init_balance':300,'init_stocks':0.5}#初始資金
fee = 0.002
nl='\n'
account_balance={'balance':0,'stocks':0}#用於交易變動的賬戶
ohlcv_dict={}
b=pd.read_csv(str(symbol[0:3])+'_30d.csv')
ohlcv_dict=b.to_dict ('list')
step_dict={}
step = 1
for key,value in ohlcv_dict.items():#將csv轉為我們需要的資料結構
step_dict[step] ={'time':key,'open':value[0],'high':value[1],'low':value[2],'close':value[3],'volume':round(value[4],4)}
step += 1
max_step=len(step_dict)
ini_market_value=step_dict[1]['high']*ini_account_dict['init_stocks']+ini_account_dict['init_balance']
print('讀取資料成功:'+nl+'初始賬戶餘額:',ini_account_dict,nl+'總市值:',ini_market_value,'USDT'+nl+'開始回測...')
def cutpoint(num,c):
num_x , num_y = str(num).split('.')
num = float(num_x+'.'+num_y[0:c])
return num
這部分還不算太複雜,主要是設定一些引數比如初始的賬戶情況和資料的呼叫作為整個回測系統的基礎資料,cutpoiont用於切個小數點,比round各種bug輸出更美觀易用。主要的函式還是下面封裝的功能類class rerun():
class rerun():
def __init__(self,progress):
self.step = progress
if self.step == 1:
self.update_balance(ini_account_dict['init_balance'],ini_account_dict['init_stocks'])
def update_balance(self,Balance,Amount):
account_balance['balance'] = Balance
account_balance['stocks'] = Amount
print('Balance updated...|'+str(symbol[0:3])+':',account_balance['stocks'],'USDT:',account_balance['balance'])
def get_account(self):
self.balance = account_balance['balance']
self.amount = account_balance['stocks']
def create_order(self, order_type, price, amount):
if order_type == 'buy':
account_balance['balance']=cutpoint(account_balance['balance']-amount,4)
account_balance['stocks']=cutpoint(account_balance['stocks']+amount/price*(1-fee),4)
log = step_dict[self.step]['time']+' 價格'+str(price)+'usdt 買入 '+str(cutpoint(amount/price,4))+symbol[0:3]
elif order_type == 'sell':
account_balance['balance']=cutpoint(account_balance['balance']+amount*price*(1-fee),4)
account_balance['stocks']=cutpoint(account_balance['stocks']-amount,4)
log = step_dict[self.step]['time']+' 價格'+str(price)+'usdt 賣出 '+str(cutpoint(amount,4))+symbol[0:3]
print(log + ' 賬戶餘額:',account_balance)
self.get_account()
def last_price(self):
self.open = step_dict[self.step]['open']
self.high = step_dict[self.step]['high']
self.low = step_dict[self.step]['low']
self.close = step_dict[self.step]['close']
self.volume = step_dict[self.step]['volume']
return self.open
def last_period(self,period):#使用者想要調取在當前step_value前多少的價格資料
self.period_list = []
for k,v in step_dict.items():
if k <= self.step-1:
self.period_list.append(v['close'])
else:
break
self.period_list = self.period_list[-period:]
return self.period_list
def sleep(self,period):#用於設定最短交易間隔
self.next_step = self.step + period+1
return self.next_step
def refresh_data(self):
self.price = self.last_price()
self.get_account()
功能和輸出的內容基本都是字面意思,而我思考了很久還是把def sleep()加進了這個class裡,用返回下一個step_value的方法告訴主函式要跳過多久,如果想到更好的方法之後再優化吧。
下面就是做一個主函式來執行想要進行的交易邏輯,交易邏輯暫定問系統要一個歷史k線,取平均值,低於平均值就買、高於就賣的簡單邏輯用於除錯功能:
def main():
next_progress = 0
for progress in range(1,max_step):
if progress<=next_progress:#跳過一部分sleep掉的step_value
continue
next_progress = trade_logic(progress)
close_value = step_dict[max_step]['close']*account_balance['stocks']
close_balance = account_balance['balance']
close_profit_rate = cutpoint(((close_value+close_balance)/ini_market_value-1)*100,2)
year_index = cutpoint(365*24*60/progress,0)
year_rate = cutpoint(((1+close_profit_rate/100)**(year_index)-1)*100,2)
print('回測結果:'+nl+'賬戶餘額:',account_balance,nl+'回測週期:',cutpoint(progress/1440,2),'天 回測週期內收益率:',close_profit_rate,'% 年化收益率:',year_rate,'%')
return
def trade_logic(progress):
period = 60
test = rerun(progress)
test.refresh_data()#重新整理一下資料讓我們可以拿到最新價格和餘額資料
price_list = test.last_period(60)
if len(price_list)<period:
return progress#資料不符合預期數量
last_price = test.price
kline_avg = np.mean(price_list)
if last_price>kline_avg*1.01 and test.amount>0.1:
test.create_order('sell',test.low,test.amount/5)
elif last_price<kline_avg*0.99 and test.balance>100:
test.create_order('buy',test.high,test.balance/5)
return test.sleep(10)
當中碰到了一個問題是如何用當前回測出的收益率來轉換成年化,最後還是忽略了誤差使用了按回測週期分割一年的時間做次方的複利思想,這部分也待優化吧。
然後看一下最後的回測效果:
讀取資料成功:
初始賬戶餘額: {'init_balance': 300, 'init_stocks': 0.5}
總市值: 595.14 USDT
開始回測...
Balance updated...|ETH: 0.5 USDT: 300
20201208_17:47:00 價格576.04usdt 買入 0.1041ETH 賬戶餘額: {'balance': 240.0, 'stocks': 0.6039}
20201208_17:59:00 價格573.76usdt 買入 0.0836ETH 賬戶餘額: {'balance': 192.0, 'stocks': 0.6873}
20201209_07:11:00 價格552.83usdt 買入 0.0694ETH 賬戶餘額: {'balance': 153.6, 'stocks': 0.7566}
20201209_15:59:00 價格539.64usdt 買入 0.0569ETH 賬戶餘額: {'balance': 122.88, 'stocks': 0.8134}
20201209_16:35:00 價格532.23usdt 買入 0.0461ETH 賬戶餘額: {'balance': 98.304, 'stocks': 0.8594}
20201209_17:11:00 價格543.37usdt 賣出 0.1718ETH 賬戶餘額: {'balance': 191.5116, 'stocks': 0.6875}
20201209_18:23:00 價格552.13usdt 賣出 0.1375ETH 賬戶餘額: {'balance': 267.2776, 'stocks': 0.55}
20201209_18:35:00 價格558.0usdt 賣出 0.11ETH 賬戶餘額: {'balance': 328.5348, 'stocks': 0.44}
20201209_18:47:00 價格558.96usdt 賣出 0.088ETH 賬戶餘額: {'balance': 377.6249, 'stocks': 0.352}
20201209_21:59:00 價格571.57usdt 賣出 0.0703ETH 賬戶餘額: {'balance': 417.7829, 'stocks': 0.2815}
20201209_22:11:00 價格572.75usdt 賣出 0.0562ETH 賬戶餘額: {'balance': 449.9642, 'stocks': 0.2251}
20201210_17:59:00 價格558.79usdt 買入 0.161ETH 賬戶餘額: {'balance': 359.9713, 'stocks': 0.3858}
20201210_18:11:00 價格558.91usdt 買入 0.1288ETH 賬戶餘額: {'balance': 287.977, 'stocks': 0.5143}
20201211_08:47:00 價格550.61usdt 買入 0.1046ETH 賬戶餘額: {'balance': 230.3816, 'stocks': 0.6186}
20201211_16:23:00 價格546.85usdt 賣出 0.1237ETH 賬戶餘額: {'balance': 297.9025, 'stocks': 0.4948}
20201212_08:23:00 價格552.12usdt 賣出 0.0989ETH 賬戶餘額: {'balance': 352.431, 'stocks': 0.3958}
20201214_00:11:00 價格589.08usdt 賣出 0.0791ETH 賬戶餘額: {'balance': 398.9693, 'stocks': 0.3166}
20201214_00:23:00 價格593.51usdt 賣出 0.0633ETH 賬戶餘額: {'balance': 436.4751, 'stocks': 0.2532}
20201214_19:11:00 價格577.44usdt 買入 0.1511ETH 賬戶餘額: {'balance': 349.18, 'stocks': 0.404}
回測結果:
賬戶餘額: {'balance': 349.18, 'stocks': 0.404}
回測週期: 6.65 天 回測週期內收益率: -1.86 % 年化收益率: -63.71 %
[Finished in 2.4s]
剩下的就是根據實際使用的情況優化細節了,比如輸出的內容,回測的迴圈方式。
今天就記錄到這裡,看到寫了很久的程式碼沒什麼令人費解的報錯還是感到很滿足的。
相關文章
- python數字貨幣量化交易開發——建立回測系統(一)Python
- 數字貨幣量化交易系統開發功能詳解丨量化交易開發原始碼模式原始碼模式
- 數字貨幣量化交易平臺 數字貨幣量化交易平臺有哪些 雲度數字貨幣量化交易 什麼是量化交易 雲度量化介紹 數字貨幣市場的量化交易工具有哪些? 量化交易需要注意什麼?
- 數字貨幣量化交易系統開發搭建執行架構指南架構
- 數字貨幣交易系統開發、數字貨幣交易平臺開發、 虛擬數字貨幣交易平臺開發、區塊鏈數字貨幣交易系統開發區塊鏈
- 數字貨幣/期貨量化交易系統開發(交易演算法)| 量化交易系統開發原始碼示例演算法原始碼
- 數字貨幣交易系統開發 數字貨幣交易軟體搭建
- 數字貨幣交易平臺開發,虛擬幣自動搬磚量化交易平臺開發
- 如何使用TradingView(TV)回測數字貨幣交易策略View
- 數字貨幣期貨合約交易系統開發,自動對衝量化交易所開發
- 幣幣交易/系統開發/現貨量化+合約交易/技術開發python示例Python
- 數字貨幣合約交易所開發,量化交易搬磚制度錢包app開發APP
- 數字貨幣交易所開發方案丨數字貨幣交易所繫統開發(正式版)丨數字貨幣交易所開發原始碼原始碼
- 數字貨幣交易系統開發,場外幣幣交易系統開發
- 數字貨幣撮合交易平臺開發,幣幣現貨交易網站軟體開發網站
- Python金融數字貨幣量化投資Python
- 免費開源數字貨幣交易所、免費開源數字貨幣交易系統、Java開源數字貨幣交易所 、Java開源數字貨幣交易系統Java
- 數字貨幣現貨交易方式 | 數字貨幣現貨交易模式系統開發定製部署模式
- 符合數字貨幣市場的量化交易系統平臺架構設計開發搭建架構
- 數字貨幣合約量化系統開發(案例詳細)丨數字貨幣合約量化成熟原始碼開發原始碼
- 數字貨幣交易所開發(海外版)丨數字貨幣交易所繫統開發(swap交易所開發案例)
- 數字貨幣交易所開發詳情丨數字貨幣交易所繫統開發(詳細及邏輯)丨數字貨幣交易所原始碼原始碼
- 數字貨幣交易所開發系統功能介紹 | 幣幣交易模式定製搭建部署模式
- 數字貨幣場外交易所開發
- 數字貨幣交易所開發(案例)丨數字貨幣交易所繫統開發(JAVA/PHP開發)及原始碼JavaPHP原始碼
- 數字貨幣交易所繫統開發(海外版)丨數字貨幣交易所開發(原始碼版)原始碼
- 數字貨幣量化交易機器人系統開發|專案測試|案例詳情|原始碼出售機器人原始碼
- 免費數字貨幣交易系統、java免費數字貨幣交易系統、免費數字資產交易系統、數字貨幣交易所開源Java
- 數字貨幣交易所借貸功能技術開發應用概述
- 青島數字貨幣交易系統開發核心
- 數字貨幣交易所開發解決方案
- 數字貨幣量化交易機器人搬磚/交易所繫統開發策略方案與步驟機器人
- 數字貨幣交易所開發正式版丨數字貨幣交易所繫統開發(開發詳情)及案例原始碼原始碼
- 數字資產BTC幣幣交易所開發期貨槓桿交易所開發
- 數字貨幣交易所開發方案,場外幣幣交易平臺搭建原始碼原始碼
- C2C數字貨幣交易平臺系統開發功能介紹
- 如何使用交易開拓者(TB)開發數字貨幣策略
- 數字貨幣交易所開發技術方案|交易平臺搭建