目录

  • 前言
    • T+0限制实现思路
  • 一、调整买卖比例并统计pnl
    • 1 - 在main中添加统计pnl
    • 2 - 调整买入比例0.98,卖出比例1.02
    • 3 - 获取pnl值
  • 二、策略添加T+0限制
    • 1 - T+0实现
    • 2 - 获取T+0限制后pnl值
  • 三、盈亏柱状图对比
    • 1 - 无T+0限制柱状图
    • 2 - T+0限制柱状图
  • 四、k线图对比
    • 1 - 无T+0限制k线图
    • 2 - T+0限制k线图
  • 五、完整源码

前言

  • 之前我们已经完成了回测,但是我们策略是ma20的单均线策略,这种策略太单一收益也不高
  • 我们需要对回归策略的单均线策略进行升级
    • 添加T+0交易限制
    • 买入需要升级为2次判断,在均线下方做一些累计计算

T+0限制实现思路

  • 其实就是在sell方法中添加上日期的判断即可

一、调整买卖比例并统计pnl

1 - 在main中添加统计pnl

if __name__ == '__main__':# 省略。。。# T = transposeorders_df = pd.DataFrame(orders).Torders_df.loc[:, 'pnl'].plot.bar()plt.show()# print sum of pnlprint('sum of pnl is: ' + str(orders_df.loc[:, 'pnl'].sum()))# 使用 mplfinance 绘制k线图:订单交易价格与时间bar5 = pd.read_csv(bar_path, parse_dates=['datetime'])bar5.loc[:, 'datetime'] = [date2num(x) for x in bar5.loc[:, 'datetime']]# 省略。。。

2 - 调整买入比例0.98,卖出比例1.02

    def strategy(self):# last < 0.95 *ma20 ,long position(仓位), last > ma20 *1.05, sellif self._is_new_bar:sum_ = 0for item in self._Close[1:21]:sum_ = sum_ + itemself._ma20 = sum_ / 20if 0 == len(self._current_orders):if self._Close[0] < 0.98 * self._ma20:# 100000/44.28 = 2258   44.28是当前价格,10万指的你拥有的钱# 2258 -> 2200 sharesvolume = int(100000 / self._Close[0] / 100) * 100self._buy(self._Close[0] + 0.01, volume)  # 这里的0.01是为了防止挂单,我们需要即可买入elif 1 == len(self._current_orders):if self._Close[0] > self._ma20 * 1.02:key = list(self._current_orders.keys())[0]self._sell(key, self._Close[0] - 0.01)# 省略。。。

3 - 获取pnl值

二、策略添加T+0限制

1 - T+0实现

    def strategy(self):# last < 0.95 *ma20 ,long position(仓位), last > ma20 *1.05, sellif self._is_new_bar:sum_ = 0for item in self._Close[1:21]:sum_ = sum_ + itemself._ma20 = sum_ / 20if 0 == len(self._current_orders):if self._Close[0] < 0.98 * self._ma20:# 100000/44.28 = 2258   44.28是当前价格,10万指的你拥有的钱# 2258 -> 2200 sharesvolume = int(100000 / self._Close[0] / 100) * 100self._buy(self._Close[0] + 0.01, volume)  # 这里的0.01是为了防止挂单,我们需要即可买入elif 1 == len(self._current_orders):if self._Close[0] > self._ma20 * 1.02:key = list(self._current_orders.keys())[0]if self._Dt[0].date() != self._current_orders[key]['open_datetime'].date():self._sell(key, self._Close[0] - 0.01)print('open date is %s, close date is: %s.'% (self._history_orders[key]['open_datetime'].date(), self._Dt[0].date()))else:# if sam dates, sell order aborted due to T+0 limitprint('sell order aborted due to T+0 limit')else:  # len() = 2raise ValueError("we have more then 1 current orders")# Close[0] in between 0.95*ma20 and 1.05*ma20,do nothing

2 - 获取T+0限制后pnl值

三、盈亏柱状图对比

1 - 无T+0限制柱状图

2 - T+0限制柱状图

四、k线图对比

1 - 无T+0限制k线图

2 - T+0限制k线图

五、完整源码

import requests
from time import sleep
from datetime import datetime, time, timedelta
from dateutil import parser
import pandas as pd
import numpy as np
import os
import matplotlib.pyplot as plt
# import mplfinance as mpf
from mplfinance.original_flavor import candlestick_ohlc
from matplotlib.dates import date2numdef get_ticks_for_backtesting(tick_path, bar_path):""":func: get ticks for backtesting, need two params:param1 tick_path: 生成的回测数据路径csv file with tick data,when there is not tick data,use bat_path to create tick dataexample: "E:\\Downloads\\600036_data\\600036_ticks.csv":param2 bar_path: 历史数据的tick路径csv file with bar data,used in creating tick dataexample: "E:\\Downloads\\600036_data\\600036_5m.csv":return: ticks in list with tuples in it, such as[(datetime, last_price), (datetime, last_price)]"""if os.path.exists(tick_path):  # 如果已存在回测数据,直接读取回测数据ticksticks = pd.read_csv(tick_path,parse_dates=['datetime'],index_col='datetime')tick_list = []for index, row in ticks.iterrows():tick_list.append((index, row[0]))# ticks = np.array(tick_list)ticks = tick_listelse:bar_5m = pd.read_csv(bar_path)  # 使用pandas读取csv数据ticks = []for index, row in bar_5m.iterrows():  # 根据不同的开盘价设置步长if row['open'] < 30:step = 0.01elif row['open'] < 60:step = 0.03elif row['open'] < 90:step = 0.05else:step = 0.1# in case of np.arrange(30, 30.11, 0.02), (open, high, step)# we will not have 30.11 as the highest price,# we might not catch high when step is more than 0.01# that is why me need: arr = np.append(arr, row['high']) and#   arr = np.append(arr, row['low'])arr = np.arange(row['open'], row['high'], step)  # 按步长生成从open到high的数据arr = np.append(arr, row['high'])  # 这个是为了弥补步长的不对等会漏掉higharr = np.append(arr, np.arange(row['open'] - step, row['low'], -step))  # 按步长生成从open到low的数据arr = np.append(arr, row['low'])  # 这个是为了弥补步长的不对等会漏掉lowarr = np.append(arr, row['close'])i = 0dt = parser.parse(row['datetime']) - timedelta(minutes=5)for item in arr:ticks.append((dt + timedelta(seconds=0.1 * i), item))  # 将数据时间模拟到0.1秒递进i += 1tick_df = pd.DataFrame(ticks, columns=['datetime', 'price'])tick_df.to_csv(tick_path, index=0)  # 保存到csv回测数据中return ticks# __init__,构造,初始化,实例化
class AstockTrading(object):""":class: A stock trading platform, needs one param,It has backtesting, paper trading, and real trading.:param1: strategy_name: strategy_name"""def __init__(self, strategy_name):self._strategy_name = strategy_nameself._Dt = []  # 交易时间self._Open = []  # 开盘价self._High = []  # 最高价self._Low = []  # 最低价self._Close = []  # 最新价self._Volume = []self._tick = []  # 数据self._last_bar_start_minute = None  # 最后一次更新bar的时间self._is_new_bar = False  # 是否有新barself._ma20 = None# 当前订单,dict, 字典self._current_orders = {}# 历史订单self._history_orders = {}self._order_number = 0self._init = False  # for backtestingdef get_tick(self):""":func: for paper trading or real trading, not for backtestingIt goes to sina to get last tick info,address is: https://hq.sinajs.cn/list=sh600519,sh600519 can be changedneed to set headers Referer to: https://finance.sina.com.cnA股的开盘时间是9:15,9:15-9:25是集合竞价 -> 开盘价,9:259:25-9:30不交易,时间>9:30,交易开始start this method after 9:25tick info is organized in tuple,such as (trade_datetime, last_price),tick info is save in self._tick.:param: no param:return: None"""headers = {'Referer': "https://finance.sina.com.cn"}page = requests.get("https://hq.sinajs.cn/list=sh600519", headers=headers)stock_info = page.textmt_info = stock_info.replace("\"", "").split("=")[1].split(",")# 最新价last = float(mt_info[1])trade_datetime = mt_info[30] + ' ' + mt_info[31]self._tick = (trade_datetime, last)def get_history_data_from_local_machine(self):""":not done yet:return:"""# tushare 数据来源# self.Open = [1, 2, 3]# self.High = [2, 3, 4]self._Open = []self._High = []self._Low = []self._Close = []self._Dt = []def bar_generator(self):""":not done yet:how save and import history data?:return:"""# assume we have history data already# 1、update bars,calculate 5 minutes ma20 , not daily data# 2、compare last and ma20  -> buy or sell or pass# assume we have history data,Open,High,Low,Close,Dt# 这里可以是5minutes、10minutes、15minutes、20minutes、30minutesif self._tick[0].minute % 5 == 0 and self._tick[0].minute != self._last_bar_start_minute:self._last_bar_start_minute = self._tick[0].minuteself._Open.insert(0, self._tick[1])self._High.insert(0, self._tick[1])self._Low.insert(0, self._tick[1])self._Close.insert(0, self._tick[1])self._Dt.insert(0, self._tick[0])self._is_new_bar = Trueelse:# update current barself._High[0] = max(self._High[0], self._tick[1])self._Low[0] = max(self._Low[0], self._tick[1])self._Close[0] = self._tick[1]self._Dt[0] = self._tick[0]self._is_new_bar = Falsedef _buy(self, price, volume):""":method: create am order:param1 price: buying price:param2 volume: buying volume:return: none"""self._order_number += 1key = "order" + str(self._order_number)self._current_orders[key] = {"open_datetime": self._Dt[0],"open_price": price,"volume": volume  # 股数}passdef _sell(self, key, price):""":method: close a long order, It needs two params:param1 key: long order's key:param2 price: selling price:return:"""self._current_orders[key]['close_price'] = priceself._current_orders[key]['close_datetime'] = self._Dt[0]self._current_orders[key]['pnl'] = \(price - self._current_orders[key]['open_price']) \* self._current_orders[key]['volume'] \- price * self._current_orders[key]['volume'] * 1 / 1000 \- (price - self._current_orders[key]['open_price']) \* self._current_orders[key]['volume'] * 3 / 10000# move order from current orders to history ordersself._history_orders[key] = self._current_orders.pop(key)def strategy(self):# last < 0.95 *ma20 ,long position(仓位), last > ma20 *1.05, sellif self._is_new_bar:sum_ = 0for item in self._Close[1:21]:sum_ = sum_ + itemself._ma20 = sum_ / 20if 0 == len(self._current_orders):if self._Close[0] < 0.98 * self._ma20:# 100000/44.28 = 2258   44.28是当前价格,10万指的你拥有的钱# 2258 -> 2200 sharesvolume = int(100000 / self._Close[0] / 100) * 100self._buy(self._Close[0] + 0.01, volume)  # 这里的0.01是为了防止挂单,我们需要即可买入elif 1 == len(self._current_orders):if self._Close[0] > self._ma20 * 1.02:key = list(self._current_orders.keys())[0]if self._Dt[0].date() != self._current_orders[key]['open_datetime'].date():self._sell(key, self._Close[0] - 0.01)print('open date is %s, close date is: %s.'% (self._history_orders[key]['open_datetime'].date(), self._Dt[0].date()))else:# if sam dates, sell order aborted due to T+0 limitprint('sell order aborted due to T+0 limit')else:  # len() = 2raise ValueError("we have more then 1 current orders")# Close[0] in between 0.95*ma20 and 1.05*ma20,do nothingdef bar_generator_for_backtesting(self, tick):""":method: for backtesting only, used to update _Open, _ High, etc, It needs just one param:param tick: tick info in tuple, (datetime, price):return:"""if tick[0].minute % 5 == 0 and tick[0].minute != self._last_bar_start_minute:self._last_bar_start_minute = tick[0].minuteself._Open.insert(0, tick[1])self._High.insert(0, tick[1])self._Low.insert(0, tick[1])self._Close.insert(0, tick[1])self._Dt.insert(0, tick[0])self._is_new_bar = Trueelse:# update current barself._High[0] = max(self._High[0], tick[1])self._Low[0] = max(self._Low[0], tick[1])self._Close[0] = tick[1]self._Dt[0] = tick[0]self._is_new_bar = Falsedef run_backtestting(self, ticks):""":method: ticks will be used to generate bars,when bars is long enough, call strategy():param ticks: list with (datetime, price) in the list:return: none"""for tick in ticks:self.bar_generator_for_backtesting(tick)if self._init:self.strategy()else:if len(self._Open) >= 100:self._init = Trueself.strategy()# ma = AstockTrading('600036')  # 类实例化
# ma.get_history_data_from_local_machine()
#
# # 交易时间是9:30-11:30,13:00-15:00
# while time(9, 26) < datetime.now().time() < time(11, 32) \
#         or time(13) < datetime.now().time() < time(15, 2):
#     ma.get_tick()
#     ma.bar_generator()
#     ma.strategy()
#     # trade_time = parser.parse(ma._tick[0]).time()
#     # sleep(3)if __name__ == '__main__':tick_path = "E:\\Downloads\\600036_data\\600036_ticks.csv"bar_path = "E:\\Downloads\\600036_data\\600036_5m.csv"ticks = get_ticks_for_backtesting(tick_path, bar_path)  # 获取回测数据ast = AstockTrading('ma')ast.run_backtestting(ticks)  # 运行回测数据print('ast._current_orders:')print(ast._current_orders)print("-------------------------------------")print('ast._history_orders:')print(ast._history_orders)# 使用matplotlib绘制盈亏柱状图profit_orders = 0  # 盈利的交易数loss_orders = 0  # 亏损的交易数orders = ast._history_ordersfor key in orders.keys():if orders[key]['pnl'] >= 0:profit_orders += 1else:loss_orders += 1win_rate = profit_orders / len(orders)loss_rate = loss_orders / len(orders)# T = transposeorders_df = pd.DataFrame(orders).Torders_df.loc[:, 'pnl'].plot.bar()plt.show()# print sum of pnlprint('sum of pnl is: ' + str(orders_df.loc[:, 'pnl'].sum()))# 使用 mplfinance 绘制k线图:订单交易价格与时间bar5 = pd.read_csv(bar_path, parse_dates=['datetime'])bar5.loc[:, 'datetime'] = [date2num(x) for x in bar5.loc[:, 'datetime']]fig, ax = plt.subplots()candlestick_ohlc(ax,quotes=bar5.values,width=0.2,colorup="r",colordown='g',alpha=1.0,)# put orders in candle sticksfor index, row in orders_df.iterrows():ax.plot([row['open_datetime'], row['close_datetime']],[row['open_price'], row['close_price']],color='darkblue',marker='o',)plt.show()

6、Python量化交易-单均线策略升级1:T+0限制相关推荐

  1. 4、Python量化交易-双均线策略

    目录 一.数据准备 二.5日均线和30日均线 1 - 均线的概念 2 - 计算5日均线与30日均线 3 - 画出MA5和MA30 三.金叉和死叉 1 - 金叉和死叉概念 2 - 分析所有金叉日期和死叉 ...

  2. Python量化交易03——海龟策略

    参考书目:深入浅出Python量化交易实战 海龟策略也是经典中的经典.其核心要点是:在股价超过过去的N天交易日的最高点时是买入信号,跌破过去的N天交易日的最低点时是卖出信号.最高点和最低点的通道被称为 ...

  3. python量化交易--择时策略

    1.在banban网爬取所有A股的股票名称和代码. 观察板板网站的股票,将在深圳上市和上海上市的A股信息爬取并保存到本地文件 2.传入股票代码,利用tushare api提取股票的所有历史数据,对股票 ...

  4. python量化交易--因子选股策略

    Fama-French三因子选股策略,三因子分别为  市场因子(股指).市值因子.账面市值比因子 三因子模型的具体步骤: 1.对股票按照市值和账面市值比分组,共计六组,市值按大小市值各50%分,账面市 ...

  5. Python量化交易实战-38使用开源项目回测双均线策略

    B站配套视频教程观看 使用PyAlgoTrade回测双均线策略 双均线策略:长短周期均线,通过金叉,死叉的方式买入卖出股票,获取收益的策略. 回顾上节课代码的部分,上节课完成了可视化代码的部分, 主要 ...

  6. Python量化交易02——双均线策略(移动平均线)

    参考书目:深入浅出Python量化交易实战 本次带来最经典的交易策略,双均线策略的构建和其回测方法. 双均线一般采用5天均值和10天均值,如果5日均线上穿突破了10日均线,说明股价在最近的涨势很猛,买 ...

  7. 使用python量化交易接口有哪些分析指标和策略?

    量化交易有哪些指标可以用于分析呢?主要有技术面和基本面可以用于分析! 来看一下技术面和基本面有什么区别? 技术面更关注具体的价格,比如每天的开盘价.收盘价.以及和开盘价/收盘价/最低价/最高价相关的K ...

  8. 《深入浅出Python量化交易实战》:散户也能学会的数字化交易策略

    前言 您可能不知道,许多专业的交易机构已经采用设定程序完成自动化交易,通过机器语言,解密盘面的走势,从而实现持续盈利的目的. (文末送读者福利) 这并非什么秘密,他们正是借助了这样的数字化工具进行操作 ...

  9. python量化交易策略实例_Python进阶量化交易场外篇3——最大回撤评价策略风险...

    新年伊始,很荣幸笔者的<教你用 Python 进阶量化交易>专栏在慕课专栏板块上线了,欢迎大家订阅!为了能够提供给大家更轻松的学习过程,笔者在专栏内容之外会陆续推出一些手记来辅助同学们学习 ...

最新文章

  1. matlab图形绘制基础(东北大学MOOC笔记)
  2. Django(part15)--页面跳转
  3. P2657-[SCOI2009]windy数【数位dp,dfs】
  4. java调用kettle例子_Kettle API - Java调用示例
  5. 读书笔记--疯狂Android讲义 目录
  6. VBA中让程序休眠 SLeep的方法
  7. JS屏蔽360浏览器代码
  8. 全面了解Nginx主要应用场景
  9. C# 重绘tabControl,添加关闭按钮(页签)
  10. 数据库 求闭包、求候选码、范式转换、最小依赖集、无损分解及保持函数依赖
  11. Data Whale第20期组队学习 Pandas学习—文本数据
  12. matplotlib绘图实现中文宋体和英文Times New Roman
  13. mysql定义过程_mysql定义和调用存储过程
  14. Centos设置开机自动启动
  15. 小孩由祖母带大会越发机灵[图]
  16. 细说php作者高洛峰免费收徒
  17. apk很小 白屏时间长_小精灵启动后会白屏很久
  18. java、vue实现微信网页分享
  19. 很遗憾未能成功连接服务器神武,神武十年《见证》逍遥游戏里的超级学霸 最希望被别人抄“作业”...
  20. 【计算机毕业设计】基于springboot的景区旅游网站

热门文章

  1. android 三星调用拍照功能吗,Android 相机开发 三星拍照崩溃修改解决 详细
  2. azure云 试用_真实世界的云迁移:Azure前门,用于全局HTTP和基于路径的负载平衡
  3. python自动化元素定位_python自动化(元素定位)
  4. 377万考研人,究竟养活了多少产业?
  5. NERF++: ANALYZING AND IMPROVING NEURAL RADIANCE FIELDS分析和改进神经辐射场
  6. Paper Reading||Improving Low-Precision Network Quantization via Bin Regularization
  7. 三维重建工具——pclpy教程之Surface(完结)
  8. Python爬取京东商品信息
  9. 学习笔记 第四周 第二篇
  10. 3. 多层select的使用:子查询的定义、无关子查询、相关子查询