一个量化平台,从demo的角度,其实非常简单,使用pandas的话,几行代码就够了,连循环都不用写。
但如果需要包含各种数据查询,流转,效率,还是需要好好设计。
数据结构,推荐pandas的dataframe,非常适合金融时间序列,尤其是技术面相关的计算,查询等。
1,benchmark,也就是回测基准,一般是指数,比如上证综指或沪深300
import math
import pandas as pd
from ..common.logger import logger
from ..datafeed import query_data
from datetime import datetime
class Benchmark(object):
def __init__(self,benchmark_code,start_date,end_date):
self.benchmark_code = benchmark_code
self.start_date = start_date
if end_date is None:
end_date = datetime.today()
self.end_date = end_date
self.load_benchmark_data()
def load_benchmark_data(self):
df = pd.DataFrame(query_data.query_symbol_dataframe(self.benchmark_code,self.start_date,self.end_date,index=True))
df['returns'] = df['close'] / df['close'].shift(1) - 1
df['equity_curve'] = (1 + df['returns']).cumprod() - 1#1股净资产曲线
logger.info('加载banchmark:%s,%s到%s数据:%d条'%(self.benchmark_code,self.start_date.strftime('%Y-%m-%d'),self.end_date.strftime('%Y-%m-%d'),len(df)))
self.data = df
def get_returns(self):
return self.data['benchmark_equity_curve'].iloc[-1] - 1
只需要如下的初始化代码:
benchmark = Benchmark('000300',datetime(2016,7,1),datetime(2017,7,1))
就加载回测周期(1年)的时间序列数据到datafram里,同时还计算好了指数的收益率(指数就按buy_and_hold)算,也没有复权的问题。
2,股票时间序列管理器。包括从服务器加载数据,本地硬盘硬盘缓存,内存缓存等。
pandas的loc,iloc按下标值,下标序号取行,然后按列名,或列序列取单元格。
先取列,再取行,可以直接使用列名,然后用下标或行值均可;
先取行,再取列,需要使用iloc用行序号,使用loc用行值。
self.assertAlmostEqual(df.loc[datetime(2016,7,1)]['close'],24.43)
self.assertAlmostEqual(df.iloc[3]['close'], 19.80)
self.assertAlmostEqual(df['factor'][0],118.416)
self.assertAlmostEqual(df['factor']['2016-07-01'],118.416)
quotes_mgr的设计也比较简单,如果内存中不存在,就去服务器读取,把回测周期内的数据一次性读入,并缓存在内存dataframe里。
import pandas as pd
from datetime import datetime
from ..datafeed import query_data
from ..common.logger import logger
class QuotesMgr(object):
'''
历史报价信息管理,服务器,本地硬盘,内存缓存机制
每次请求都是回测周期里的所有数据,dataframe格式
'''
def __init__(self,start_date,end_date=None):
self.all_symbol_dfs = {}
self.start_date = start_date
self.end_date = end_date
if self.end_date is None:
self.end_date = datetime.today()
def get_symbol_dataframe(self,symbol):
if symbol not in self.all_symbol_dfs.keys():
logger.debug('symbol未发现,从服务器获取。')
self.all_symbol_dfs[symbol] = query_data.query_symbol_dataframe(symbol, start_date=self.start_date,
end_date=self.end_date)
df = self.all_symbol_dfs[symbol]
return df
#按date取数据
def get_symbol_bar(self,symbol,date):
df = self.get_symbol_dataframe(symbol)
if df is None or len(df) == 0:
logger.error('取symbol:%s,date:%s错误'%(symbol,date.strftime('%Y-%m-%d')))
return None
return df.loc[date]
#取symbol某date的一个字段,比如close值
def get_symbol_bar_value(self,symbol,date,key='close'):
return self.get_symbol_bar(symbol,date)[key]
def get_symbol_bar_list(self,symbol,N=5,key='close'):
df = self.get_symbol_dataframe(symbol)
if df is None or len(df) == 0:
logger.error('get_symbol_bar_list %s错误' %(symbol))
return None
return df[key][-N:]
如上,完成了基础数据准备,有benckmark数据,有日K,包括市值,交易量,换手率,PE,PB等和价格相关的数据,都可以取到。
3,投资组合管理。
在回测系统里,投资组合相当于是一个账本。一本账是仓位,一本账是市值。
联系客服