13 篇文章 3 订阅
11 篇文章 2 订阅
3 篇文章 1 订阅

# 1、模块导入

import akshare as ak
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from collections import namedtuple
from collections import OrderedDict
from collections.abc import Iterable
from functools import reduce
from abc import ABC, abstractmethod


akshare：用于下载股票的交易数据(前复权)
collections：对基本数据类型做进一步处理,实现特定的数据类型
abc：主要定义了基本类和最基本的抽象方法，可以为子类定义共有的接口API，不需要具体实现

# 2、数据获取

# 获取某一只股票一段时间的数据
stock_sz300750_df = ak.stock_zh_a_daily(symbol="sz300750", start_date="20200103", end_date="20211231", adjust="qfq")
# list_date = list(stock_sz300750_df['date'])
# stock_sz300750_df.index = list_date


# 3、股票数据类型转换

# 将股票数据转化为新的数据类型
def __init__(self, price_array, date_array=None):
self.price_array = price_array
self.date_array = self._init_days(date_array)
self.change_array = self._init_change()
self.s_short = self._init_sma_short(price_array)
self.s_long = self._init_sma_long(price_array)
self.stock_dict = self._init_stock_dict()

def _init_change(self):
# 收益率

change_array = self.price_array.pct_change(periods=1)
return change_array

def _init_days(self, date_array):
# 日期序列

date_array = [str(date) for date in date_array]
return date_array

def _init_sma_short(self, price_array):
# 5日移动平均线

s_short = price_array.rolling(window=5, min_periods=5).mean()
return s_short

def _init_sma_long(self, price_array):
# 30日移动平均线

s_long = price_array.rolling(window=30, min_periods=30).mean()
return s_long

def _init_stock_dict(self):
# 将股票的日期、收盘价、涨跌幅转化为一个新的数据类型

stock_namedtuple = namedtuple('stock', ('date', 'price', 'change', 's_short', 's_long'))

# 使用以被赋值的date_array等进行OrderedDict的组装
stock_dict = OrderedDict((date, stock_namedtuple(date, price, change, s_short, s_long)) for date, price, change, s_short, s_long
in zip(self.date_array, self.price_array, self.change_array, self.s_short, self.s_long))
return stock_dict

def filter_stock(self, want_up=True, want_calc_sum=False):
# 判断交易日股票是上涨还是下跌
# 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


trade_days = StockTradeDays(stock_sz300750_df['close'], stock_sz300750_df['date'])
print(day)


# 4、回测系统编写

class TradeStrategyBase(ABC, object):   # 只能被继承，不能实例化
# 交易策略抽象基类

@abstractmethod
# 买入策略基类
pass

@abstractmethod
def sell_strategy(self, *args, **kwargs):
# 卖出策略基类
pass

# 交易回测系统

"""
"""
# 交易盈亏结果序列
self.profit_array = []

# 执行交易回测

# 以时间驱动，完成交易回测

# 如果有持有股票，加入交易盈亏结果序列
self.profit_array.append(day.change)
#                 print("日期：{}，持有中".format(day.date))

# hasattr: 用来查询对象有没有实现某个方法
# 买入策略执行
#                     print("日期：{}，买入策略执行".format(day.date))

# 卖出策略执行
#                     print("日期：{}，卖出策略执行".format(day.date))


# 5、策略编写

class TradeStrategy1(TradeStrategyBase):
"""
交易策略1: 利用5日移动平均线与30日移动平均线交叉点进行股票买卖
当5日移动平均线从下往上穿过30日移动平均线时，买入股票并持有
当5日移动平均线从上往下穿过30日移动平均线时，卖出股票
"""
def __init__(self, stock_df):
self.keep_stock_day = -1

# 只有当长期移动平均线的数据有了，才能进行下一步操作

# 今日移动平均线值

# 昨日移动平均线值

if today_short > today_long and yesterday_short < yesterday_long:
# 买入条件成立：
self.keep_stock_day = 1

# 只有当长期移动平均线的数据有了，才能进行下一步操作

# 今日移动平均线值

# 昨日移动平均线值

if today_short < today_long and yesterday_short > yesterday_long:
# 卖出条件成立：
self.keep_stock_day = 0


class TradeStrategy2(TradeStrategyBase):
"""
交易策略2: 追涨杀跌策略，当股价连续两个交易日上涨
当股价连续两个交易日下跌
且下跌幅度超过阀值默认s_sell_change_threshold()，卖出股票
"""
def __init__(self):
self.keep_stock_day = 0
self.s_sell_change_threshold = -0.05   #下跌卖出阀值

if self.keep_stock_day == 0 and trade_ind >= 1:
"""
当没有持有股票的时候self.keep_stock_day == 0 并且
"""
# 昨天是否股价上涨
# 两天总涨幅
if today_down and yesterday_down and down_rate > self.s_buy_change_threshold:
self.keep_stock_day += 1

# 昨天是否股价下跌
# 两天总跌幅
if today_down and yesterday_down and down_rate < self.s_sell_change_threshold:
# 卖出条件成立：连跌两天，跌幅超过s_sell_change_threshold
self.keep_stock_day = 0

@property
# getter获取属性函数

# setter属性赋值
"""
上涨阀值需要为float类型
"""
# 上涨阀值只取小数点后两位

@property
def s_sell_change_threshold(self):
# getter获取属性函数
return self.__s_sell_change_threshold

@s_sell_change_threshold.setter
def s_sell_change_threshold(self, s_sell_change_threshold):
# setter属性赋值
if not isinstance(s_sell_change_threshold, float):
"""
上涨阀值需要为float类型
"""
# 上涨阀值只取小数点后两位
self.__s_sell_change_threshold = round(s_sell_change_threshold, 2)


# 6、实例化策略

# 实例化策略1
print('回测策略1总盈亏为：{}%'.format(reduce(lambda a, b: a + b, trade_loop_back.profit_array) * 100))


# 实例化策略2
print('回测策略2总盈亏为：{}%'.format(reduce(lambda a, b: a + b, trade_loop_back.profit_array) * 100))


# 非面向对象的编程

changes_list_1 = []
flag = -1
short2 = day.s_short
long2 = day.s_long
if pd.isna(long1):
continue
if flag == 1:
changes_list_1.append(day.change)
print("日期：{}，持有中".format(day.date))
if short2 > long2 and short1 < long1:
flag = 1
print("日期：{}，买入策略执行".format(day.date))
if short2 < long2 and short1 > long1:
flag = 0
print("日期：{}，卖出策略执行".format(day.date))

print('回测策略1总盈亏为：{}%'.format(reduce(lambda a, b: a + b, changes_list_1) * 100))
plt.plot(np.array(changes_list_1).cumsum())


# 策略2
changes_list_2 = []
flag = 0
today_down = day.change
if flag > 0:
changes_list_2.append(day.change)
print("日期：{}，持有中".format(day.date))
if today_down > 0 and yesterday_down > 0 and today_down + yesterday_down > 0.01:
flag += 1
print("日期：{}，买入策略执行".format(day.date))
if today_down < 0 and yesterday_down < 0 and today_down + yesterday_down < -0.01:
flag = 0
print("日期：{}，卖出策略执行".format(day.date))

print('回测策略2总盈亏为：{}%'.format(reduce(lambda a, b: a + b, changes_list_2) * 100))
plt.plot(np.array(changes_list_2).cumsum())


# 分析总结

06-18 430
04-22 6530
11-26 268
07-26 4275
03-19 2947
07-02 5176
06-07 3097
06-14 297

### “相关推荐”对你有帮助么？

• 非常没帮助
• 没帮助
• 一般
• 有帮助
• 非常有帮助

¥2 ¥4 ¥6 ¥10 ¥20

1.余额是钱包充值的虚拟货币，按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载，可以购买VIP、C币套餐、付费专栏及课程。