1 Star 0 Fork 109

xindeluoye/abu

forked from 笨人贱/abu 
加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
文件
克隆/下载
stock_days.py 9.36 KB
一键复制 编辑 原始数据 按行查看 历史
bbfamily 提交于 2017-08-23 10:52 . abu量化交易系统0.10
# -*- encoding:utf-8 -*-
from abc import ABCMeta, abstractmethod
from collections import OrderedDict
from collections import namedtuple
from abupy import six, reduce, map, filter
class StockTradeDays(object):
def __init__(self, price_array, start_date, date_array=None):
# 私有价格序列
self.__price_array = price_array
# 私有日期序列
self.__date_array = self._init_days(start_date, date_array)
# 私有涨跌幅序列
self.__change_array = self.__init_change()
# 进行OrderedDict的组装
self.stock_dict = self._init_stock_dict()
def __init_change(self):
"""
从price_array生成change_array
:return:
"""
price_float_array = [float(price_str) for price_str in
self.__price_array]
# 通过将时间平移形成两个错开的收盘价序列,通过zip打包成为一个新的序列
# 每个元素为相邻的两个收盘价格
pp_array = [(price1, price2) for price1, price2 in
zip(price_float_array[:-1], price_float_array[1:])]
change_array = list(map(lambda pp: reduce(lambda a, b: round((b - a) / a, 3), pp), pp_array))
# list insert插入数据,将第一天的涨跌幅设置为0
change_array.insert(0, 0)
return change_array
def _init_days(self, start_date, date_array):
"""
protect方法,
:param start_date: 初始日期
:param date_array: 给定日期序列
:return:
"""
if date_array is None:
# 由start_date和self.__price_array来确定日期序列
date_array = [str(start_date + ind) for ind, _ in
enumerate(self.__price_array)]
else:
# 稍后的内容会使用外部直接设置的方式
# 如果外面设置了date_array,就直接转换str类型组成新date_array
date_array = [str(date) for date in date_array]
return date_array
def _init_stock_dict(self):
"""
使用namedtuple,OrderedDict将结果合并
:return:
"""
stock_namedtuple = namedtuple('stock',
('date', 'price', 'change'))
# 使用以被赋值的__date_array等进行OrderedDict的组装
stock_dict = OrderedDict(
(date, stock_namedtuple(date, price, change))
for date, price, change in
zip(self.__date_array, self.__price_array,
self.__change_array))
return stock_dict
def filter_stock(self, want_up=True, want_calc_sum=False):
"""
筛选结果子集
:param want_up: 是否筛选上涨
:param want_calc_sum: 是否计算涨跌和
:return:
"""
# Python中的三目表达式的写法
filter_func = (lambda p_day: p_day.change > 0) if want_up else (
lambda p_day: p_day.change < 0)
# 使用filter_func做筛选函数
want_days = list(filter(filter_func, self.stock_dict.values()))
if not want_calc_sum:
return want_days
# 需要计算涨跌幅和
change_sum = 0.0
for day in want_days:
change_sum += day.change
return change_sum
"""
下面的__str__,__iter__, __getitem__, __len__稍后会详细讲解作
"""
def __str__(self):
return str(self.stock_dict)
__repr__ = __str__
def __iter__(self):
"""
通过代理stock_dict的跌倒,yield元素
:return:
"""
for key in self.stock_dict:
yield self.stock_dict[key]
def __getitem__(self, ind):
date_key = self.__date_array[ind]
return self.stock_dict[date_key]
def __len__(self):
return len(self.stock_dict)
class TradeStrategyBase(six.with_metaclass(ABCMeta, object)):
"""
交易策略抽象基类
"""
@abstractmethod
def buy_strategy(self, *args, **kwargs):
# 买入策略基类
pass
@abstractmethod
def sell_strategy(self, *args, **kwargs):
# 卖出策略基类
pass
class TradeStrategy1(TradeStrategyBase):
"""
交易策略1: 追涨策略,当股价上涨一个阀值默认为7%时
买入股票并持有s_keep_stock_threshold(20)天
"""
s_keep_stock_threshold = 20
def __init__(self):
self.keep_stock_day = 0
# 7%上涨幅度作为买入策略阀值
self.__buy_change_threshold = 0.07
def buy_strategy(self, trade_ind, trade_day, trade_days):
if self.keep_stock_day == 0 and \
trade_day.change > self.__buy_change_threshold:
# 当没有持有股票的时候self.keep_stock_day == 0 并且
# 符合买入条件上涨一个阀值,买入
self.keep_stock_day += 1
elif self.keep_stock_day > 0:
# self.keep_stock_day > 0代表持有股票,持有股票天数递增
self.keep_stock_day += 1
def sell_strategy(self, trade_ind, trade_day, trade_days):
if self.keep_stock_day >= \
TradeStrategy1.s_keep_stock_threshold:
# 当持有股票天数超过阀值s_keep_stock_threshold,卖出股票
self.keep_stock_day = 0
"""
property属性稍后会讲到
"""
@property
def buy_change_threshold(self):
return self.__buy_change_threshold
@buy_change_threshold.setter
def buy_change_threshold(self, buy_change_threshold):
if not isinstance(buy_change_threshold, float):
"""
上涨阀值需要为float类型
"""
raise TypeError('buy_change_threshold must be float!')
# 上涨阀值只取小数点后两位
self.__buy_change_threshold = round(buy_change_threshold, 2)
class TradeLoopBack(object):
"""
交易回测系统
"""
def __init__(self, trade_days, trade_strategy):
"""
使用上一节封装的StockTradeDays类和本节编写的交易策略类
TradeStrategyBase类初始化交易系统
:param trade_days: StockTradeDays交易数据序列
:param trade_strategy: TradeStrategyBase交易策略
"""
self.trade_days = trade_days
self.trade_strategy = trade_strategy
# 交易盈亏结果序列
self.profit_array = []
def execute_trade(self):
"""
执行交易回测
:return:
"""
for ind, day in enumerate(self.trade_days):
"""
以时间驱动,完成交易回测
"""
if self.trade_strategy.keep_stock_day > 0:
# 如果有持有股票,加入交易盈亏结果序列
self.profit_array.append(day.change)
# hasattr: 用来查询对象有没有实现某个方法
if hasattr(self.trade_strategy, 'buy_strategy'):
# 买入策略执行
self.trade_strategy.buy_strategy(ind, day,
self.trade_days)
if hasattr(self.trade_strategy, 'sell_strategy'):
# 卖出策略执行
self.trade_strategy.sell_strategy(ind, day,
self.trade_days)
class TradeStrategy2(TradeStrategyBase):
"""
交易策略2: 均值回复策略,当股价连续两个交易日下跌,
且下跌幅度超过阀值默认s_buy_change_threshold(-10%),
买入股票并持有s_keep_stock_threshold(10)天
"""
# 买入后持有天数
s_keep_stock_threshold = 10
# 下跌买入阀值
s_buy_change_threshold = -0.10
def __init__(self):
self.keep_stock_day = 0
def buy_strategy(self, trade_ind, trade_day, trade_days):
if self.keep_stock_day == 0 and trade_ind >= 1:
"""
当没有持有股票的时候self.keep_stock_day == 0 并且
trade_ind >= 1, 不是交易开始的第一天,因为需要yesterday数据
"""
# trade_day.change < 0 bool:今天是否股价下跌
today_down = trade_day.change < 0
# 昨天是否股价下跌
yesterday_down = trade_days[trade_ind - 1].change < 0
# 两天总跌幅
down_rate = trade_day.change + trade_days[trade_ind - 1].change
if today_down and yesterday_down and down_rate < \
TradeStrategy2.s_buy_change_threshold:
# 买入条件成立:连跌两天,跌幅超过s_buy_change_threshold
self.keep_stock_day += 1
elif self.keep_stock_day > 0:
# self.keep_stock_day > 0代表持有股票,持有股票天数递增
self.keep_stock_day += 1
def sell_strategy(self, trade_ind, trade_day, trade_days):
if self.keep_stock_day >= \
TradeStrategy2.s_keep_stock_threshold:
# 当持有股票天数超过阀值s_keep_stock_threshold,卖出股票
self.keep_stock_day = 0
"""
稍后会详细讲解classmethod,staticmethod
"""
@classmethod
def set_keep_stock_threshold(cls, keep_stock_threshold):
cls.s_keep_stock_threshold = keep_stock_threshold
@staticmethod
def set_buy_change_threshold(buy_change_threshold):
TradeStrategy2.s_buy_change_threshold = buy_change_threshold
Loading...
马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化
Python
1
https://gitee.com/XGSEN/abu.git
git@gitee.com:XGSEN/abu.git
XGSEN
abu
abu
master

搜索帮助