回测是一个股票接口的最基础功能了,一般只要不是做的很差,基本上都靠谱,只不过有的比较难以理解罢了,但有的有一定的技术优势。比如第一报错:可能行情没有这么久,返回了None,直接引用就会出错。这些编程语言往往需要自己考虑好各种错误,而麦语言这种,语法简单,但可定制化的程度不强,有时候会编程的用着感觉会更麻烦。
当然,再好的工具也不及自己写,我们拿到数据接口以后,完全可以自己写回测函数,,定的策略是如果买入,则会购买半成仓位,如果卖出,同样是卖出半成仓位。对应的回测代码如下:
import datetime
from quantitative.data_process import get_day_name_data
from quantitative.rsrs import sell_or_buy
class BackTrader:
def __init__(self,
cash: float = 50000,
stock: str = "000001",
reverso: float = 0):
"""
构造回测对象。根据输入的股票代码,然后给定资金池,模拟买入卖出。
:param cash: 初始资金数量 float
:param stock: 股票代码 str
:param reverso: 每次交易手续费率 float
"""
# 利用数据,初始化交易所对象和策略对象。
self.stock = stock # 股票代码
self.init_cash = cash # 初始投入资金
self.cash = cash # 当前现金持有量
self.lst = [] # 股票池
self.buy_num = 0 # 总计买入的股票数量
self.sell_num = 0 # 总计卖出的股票数量
def sell(self, close, closeout=False):
price = close * 100 # 一手的价格
sell_num = len(self.lst) // 2
if closeout: # 强制平仓,
self.cash += len(self.lst) * price
self.lst = [] # 股票池没有股票了
self.sell_num += len(self.lst)
elif len(self.lst) == 0: # 这个表示没有持仓
print(f'没有持仓哦,无法卖出股票')
pass
elif len(self.lst) == 1: # 只有一手股票
self.cash += price
self.lst.pop()
self.sell_num += 1
else: # 多于两手股票
#
for i in range(sell_num):
self.cash += price
self.lst.pop()
self.sell_num += 1
print(f'卖出了{sell_num}手股票,当前持有股票量{len(self.lst)},当前现金持有量{self.cash}')
def buy(self, close):
price = close * 100 # 一手的价格
try:
num = int(self.cash // price)
if num == 0:
print("Oh,sorry,没有现金了")
pass
if num == 1:
self.buy_num += 1
self.lst.append(price)
print(f'现金不多了,仅可以买入1手哦')
else:
buy_num = num // 2
print(f'金主,你可以买入{num}手,买入了{buy_num}手')
for i in range(buy_num):
self.lst.append(price)
self.cash -= price
self.buy_num += buy_num
print(f'当前现金持有量{self.cash},股票持有量{len(self.lst)}')
except:
print(f'{price} 是不可以运算的')
def run(self, begin, end):
"""
运行回测,迭代历史数据,执行模拟交易并返回回测结果。
"""
begin_date = datetime.datetime.strptime(begin, "%Y-%m-%d")
end_date = datetime.datetime.strptime(end, "%Y-%m-%d")
days = (end_date - begin_date).days
close = 0
for i in range(days):
date_str = (begin_date + datetime.timedelta(days=i)).strftime("%Y-%m-%d")
flag = sell_or_buy(self.stock, date_str)
close = get_day_name_data(self.stock, date_str, "收盘价")
if isinstance(close, str):
continue
if flag == "BUY":
self.buy(close)
elif flag == "SELL":
self.sell(close)
if i == days - 1: # 最后一天强制平仓
self.sell(close)
# print(self.cash)
self.cash += len(self.lst) * close
print(self.cash)
print("收益率", (self.cash - self.init_cash) / self.init_cash)
print(self.lst)
print("购买次数", self.sell_num)
print("出售次数", self.buy_num)
# 每日数据更新,寻找股票数据,需要判断当日的数据是否已经写入到数据库中了
def get_stock_code():
from database import MG
from database import MONGO_STOCK
client = MG(MONGO_STOCK)
stock_code = client.db['stock_code']
# 查找整个中国所有的股票
res = stock_code.find({})
for i, item in enumerate(res):
yield item['证券简称'], item['code']
if __name__ == '__main__':
for item in get_stock_code():
bt = BackTrader(cash=50000, stock=item[1])
begin = "2022-01-10"
end = "2022-06-30"
bt.run(begin, end)
print(item)
好了,所以什么样数据接口适合使用呢?这里有一个大家可以了解一下的:获取比较简单,https://gitee.com/l2gogogo就可以找到,也支持Python语言,拿到账号就可以订阅,然后我们自己再做二次开发就可以对接写策略了,