(于北京疫情期间)
量化之所以做为投资的手段,早应该有共识了。下围棋象棋的人知道, 人脑不可能战胜有智能的程序,它的计算能力太强太快,加上严格的程序化执行。我们人在做交易的时候,受情绪身体状况影响,感知的偏差,消息的不对称,往往会经常性的犯错。
我们的量化历程也是发展的很不顺利,从最初C++Fix协议注重高频交易,C#算法编程。到如今终于归入正道,发现Python才是一统江山的金融量化的工具,而我们现在用的Backtrader更可以称为国之重器!为什么呢? 首先它有强大丰富的支持库,简单易用且成熟。 具体对我们来说就是金融数据分析应用方面引用库numpy,pandas和matplotlib。可以非常快速部署,性能稳定高效。
又为什么说它一统江山呢?外汇,加密货币和金融股指期货可以一并用它作为量化工具了:
- FX-外汇有 IB, OANDA可以支持用(策略难度最高)
- 加密货币的大部分交易所;我们现在用OKex,Binance (难度适中)
- 国内的股指商品期货极星量化交易可以用 (相对简单)
通用的解决方案是Python封装API接口。这大大简化了各个平台策略开发。相信国内外宽客的同行团队越来越多的会像我们一样,转向Python-BT。也许很快就发展成为新的行业标准。
下面是BT应用的一个简单实例,只需要几分钟就安装好了,在你的Python的 IDE环境运行一下,看你是否认同它的强大简单和高效!?
首先安装BACKTRADER
pip install backtrader pip install backtrader[plotting]
下面我们运行一个简单的策略,将symbol orcl一年的数据导入策略运行,结果显示导入数据和价格曲线以图形方式绘制出来。设定起始资金,用这次导入价格数据运行后显示交易记录和资金状况。
下面是数据文件的链接,浏览打开另存到本地文件夹,程序中默认路径为当前程序目录。请根据需要修改。
https://nabidex.com/usercontent/orcl-1995-2014.txt
数据文件存好后, 复制下面的程序就可以运行了,结果看后面的截图。
#this source code is provided by Backtrader Team! from __future__ import (absolute_import,division,print_function,unicode_literals) import datetime # For datetime objects import os.path # To manage paths import sys # To find out the script name (in argv[0]) # Import the backtrader platform import backtrader as bt # Create a Stratey class TestStrategy(bt.Strategy): params = ( ('maperiod', 15), ) def log(self, txt, dt=None): ''' Logging function fot this strategy''' dt = dt or self.datas[0].datetime.date(0) print('%s, %s' % (dt.isoformat(), txt)) def __init__(self): # Keep a reference to the "close" line in the data[0] dataseries self.dataclose = self.datas[0].close # To keep track of pending orders and buy price/commission self.order = None self.buyprice = None self.buycomm = None # Add a MovingAverageSimple indicator self.sma = bt.indicators.SimpleMovingAverage( self.datas[0], period=self.params.maperiod) # Indicators for the plotting show bt.indicators.ExponentialMovingAverage(self.datas[0],period=25) bt.indicators.WeightedMovingAverage(self.datas[0],period=25,subplot=True) bt.indicators.StochasticSlow(self.datas[0]) bt.indicators.MACDHisto(self.datas[0]) rsi = bt.indicators.RSI(self.datas[0]) bt.indicators.SmoothedMovingAverage(rsi,period=10) bt.indicators.ATR(self.datas[0],plot=False) def notify_order(self, order): if order.status in [order.Submitted, order.Accepted]: # Buy/Sell order submitted/accepted to/by broker - Nothing to do return # Check if an order has been completed # Attention: broker could reject order if not enough cash if order.status in [order.Completed]: if order.isbuy(): self.log( 'BUY EXECUTED, Price: %.2f, Cost: %.2f, Comm %.2f' % (order.executed.price, order.executed.value, order.executed.comm)) self.buyprice = order.executed.price self.buycomm = order.executed.comm else: # Sell self.log('SELL EXECUTED, Price: %.2f, Cost: %.2f, Comm %.2f' % (order.executed.price, order.executed.value, order.executed.comm)) self.bar_executed = len(self) elif order.status in [order.Canceled, order.Margin, order.Rejected]: self.log('Order Canceled/Margin/Rejected') # Write down: no pending order self.order = None def notify_trade(self, trade): if not trade.isclosed: return self.log('OPERATION PROFIT, GROSS %.2f, NET %.2f' % (trade.pnl, trade.pnlcomm)) def next(self): # Simply log the closing price of the series from the reference self.log('Close, %.2f' % self.dataclose[0]) # Check if an order is pending ... if yes, we cannot send a 2nd one if self.order: return # Check if we are in the market if not self.position: # Not yet ... we MIGHT BUY if ... if self.dataclose[0] > self.sma[0]: # BUY, BUY, BUY!!! (with all possible default parameters) self.log('BUY CREATE, %.2f' % self.dataclose[0]) # Keep track of the created order to avoid a 2nd order self.order = self.buy() else: if self.dataclose[0] < self.sma[0]: # SELL, SELL, SELL!!! (with all possible default parameters) self.log('SELL CREATE, %.2f' % self.dataclose[0]) # Keep track of the created order to avoid a 2nd order self.order = self.sell() if __name__ == '__main__': # Create a cerebro entity cerebro = bt.Cerebro() # Add a strategy cerebro.addstrategy(TestStrategy) # Datas are in a subfolder of the samples. Need to find where the script is # because it could have been called from anywhere modpath = os.path.dirname(os.path.abspath(sys.argv[0])) datapath = os.path.join(modpath, 'orcl-1995-2014.txt') # Create a Data Feed data = bt.feeds.YahooFinanceCSVData( dataname=datapath, # Do not pass values before this date fromdate=datetime.datetime(2000, 1, 1), # Do not pass values before this date todate=datetime.datetime(2000, 12, 31), # Do not pass values after this date reverse=False) # Add the Data Feed to Cerebro cerebro.adddata(data) # Set our desired cash start cerebro.broker.setcash(1000.0) # Add a FixedSize sizer according to the stake cerebro.addsizer(bt.sizers.FixedSize, stake=10) # Set the commission cerebro.broker.setcommission(commission=0.0) # Print out the starting conditions print('Starting Portfolio Value: %.2f' % cerebro.broker.getvalue()) # Run over everything cerebro.run() # Print out the final result print('Final Portfolio Value: %.2f' % cerebro.broker.getvalue()) # Plot the result cerebro.plot()
最后是运行后的截图:

欢迎同行加入我们的群组交流讨论!
