1-2 移动均线交叉策略1

第一阶段、一个简单策略入门量化投资

1-2 移动均线交叉策略1

  • 第一阶段一个简单策略入门量化投资
  • 1-2 移动均线交叉策略1
    • 前言
    • 获取数据
    • 移动均线交叉策略
    • 数据可视化
      • 绘制折线图
      • 绘制K线图
      • 绘制移动均线
    • 移动均线交叉策略回测
      • 什么是回测
      • 回溯买卖信号
      • 计算收益
    • 未完待续
    • 完整代码

前言

本学期订了两个目标:探索量化投资与熟练掌握python
以量化投资为切入点,以python为工具,在研究策略过程中又可以练习python,两个目标相辅相成,想法很美好,于是就有了此文。
作为一个初学者,我定下了第一阶段的目标:
通过一个简单策略,梳理研究并编写一个交易策略的整个流程,从而入门量化投资。
我在网上找到了一篇不错的入门教程:
Python股市数据分析教程——学会它,或可以实现半“智能”炒股 (Part 1)
这也是我的主要参考资料,本文是在此基础上梳理出来的,也可以说是学习过程的记录。下面开始正文


获取数据

在1-1股票数据预处理练习中我们已经介绍了如何获取一只股票的数据并且进行一定的修改以满足我们的需要
使用如下代码,获取苹果公司2010年至今的股票数据

import numpy as np
import pandas as pd
import pandas_datareader.data as web
import datetime
import time##### get historical data of a stock
# the first time we get the stock data from the interface of yahoo
# but we may not want to do this step all the time, so we try to save it in .csv
#start = datetime.datetime(2016, 1, 1)
#end = datetime.date.today()
#apple = web.DataReader("AAPL", "yahoo", start, end)
#print(apple.head())
#apple.to_csv(path_or_buf='data_AAPL.csv')##### read the data from csv
apple=pd.read_csv(filepath_or_buffer='data_AAPL.csv')
print(apple.head())
# note that some format(data type) of data we read from .csv has changed
# for example the attribute 'Date' should be the index of the dataframe, and the date type changed from datetime to string
# this changes would made some methods got trouble
# So we need to make the following changes
date_list = []
for i in range(len(apple)):date_str = apple['Date'][i]t = time.strptime(date_str, "%Y-%m-%d")temp_date = datetime.datetime(t[0], t[1], t[2])date_list.append(temp_date)
apple['DateTime'] = pd.Series(date_list,apple.index)
del apple['Date']
apple = apple.set_index('DateTime')

这样,数据准备工作就完成了

移动均线交叉策略

许多交易策略都试图去找到股票价格的趋势,移动均线交叉策略就是其中最简单的一种。我们来讨论下它是如何工作的。
什么是移动均线?
对于序列xt以及时刻t,q天均线表示过去q天股价的均值:也就是说,如果MAtq表示t时刻的q天均线,那么:
这里写图片描述
显然,移动均线平滑了数据序列,并有助于识别股市的发展趋势。q值越大,移动均线就越难反映序列xt中的短期波动,但也更好的把握了整体的趋势。
什么是均线交叉策略
均线交叉策略的想法是,利用一长一短两条移动均线能够从”噪声”中识别股市的发展趋势。短期均线具有较小的q值,比较紧密地跟随股票的趋势发展,更能代表短期内的股价变动;而长期均线的q值较大,进而使得均线对股票波动的响应较小,而且更加平稳。
因此,移动均线交叉策略描述如下:
当短期均线超越长期均线时,说明股票价格短期内程上涨的趋势,我们将这时作为买入时机。当短期均线跌落到长期均线以下时,认为牛市结束,将股票卖出。
下面,我们通过可视化的方法,绘制出股票的历史数据图,以及两条长短均线,来直观的感受下这个策略。

数据可视化

绘制折线图

我们利用获取的数据中的股票收盘价,绘制出相应的折线图。

apple["Adj Close"].plot(grid=True)

收盘价历史数据折线图

绘制K线图

很显然这种表达过于单调,而且我们获取的数据还包含开盘价、最高价、最低价这些信息没有使用。
众所周知,金融数据通常以日本蜡烛图(即K线图)的形式绘制,这种图表最早在18世纪由日本米市商人命名。matplotlib可以绘制这样的图表,但操作起来比较复杂。于是此文的作者实现了一个函数,可以更容易地在pandas数据框架中创建蜡烛图,并使用它绘制我们的股票数据。你还可以参考matplotlib提供的示例 戳这里.
我们调用这个函数,来可视化股票数据(代码可在文末查看)。

draw_candle.pandas_candlestick_ohlc(apple,stick = 'month')

其中stick参数用于指明绘制每个“小蜡烛”的时间间隔,效果如下:
这里写图片描述

绘制移动均线

首先为苹果股票创建了三条移动均线,滑动平均的范围分别是20天、50天、200天。随后,将其与股票数据一同绘制在图表中。
pandas提供了轻松计算移动均线的功能,下面的代码展示了这部分功能。

apple["20d"] = np.round(apple["Close"].rolling(window = 20, center = False).mean(), 2)
apple["50d"] = np.round(apple["Close"].rolling(window = 50, center = False).mean(), 2)
apple["100d"] = np.round(apple["Close"].rolling(window = 200, center = False).mean(), 2)
draw_candle.pandas_candlestick_ohlc(apple.loc['2016-01-04':'2017-09-01',:],stick='week',otherseries = ["20d", "50d", "100d"])

这里写图片描述
多多观察不同滑动长度的移动均线组合而成的交叉策略,以及均线交叉策略作用在不同股票上的图表,能够对该策略有一些更好的认识。

移动均线交叉策略回测

什么是回测

股票回测是指设定了某些股票策略后,基于历史已经发生过的真实行情数据,在历史上某一个时间点开始,严格按照设定的组合进行选股,并模拟真实金融市场交易的规则进行模型买入、模型卖出,得出一个时间段内的盈利率、最大回撤率等数据。
回测是股票模型创建中必不可少的环境,虽然回测效果非常好的策略实盘也不一定表现好,但连回测效果都不好的策略,就无法立足了。

回溯买卖信号

我们现在依照移动均线交叉策略的规则,回溯出在苹果股票上利用该策略产生的买卖信号,进而方便后面计算策略收益。
依照已经制定的策略,定义买卖点如下:
买点:短期均线>长期均线
卖点:短期均线<=长期均线
这个过程可通过下面代码完成:

##### compute the sub of the long time span moving average and the short one
# use regime to represent it
apple['20d-50d'] = apple['20d'] - apple['50d']
apple["Regime"] = np.where(apple['20d-50d'] > 0, 1, 0)
apple["Regime"] = np.where(apple['20d-50d'] < 0, -1, apple["Regime"])
regime_count = apple["Regime"].value_counts()##### use Regime to compute the trading signal
regime_orig = apple.ix[-1, "Regime"]
apple.ix[-1, "Regime"] = 0
apple["Signal"] = np.sign(apple["Regime"] - apple["Regime"].shift(1))
apple.ix[-1, "Regime"] = regime_orig##### build the trading signal dataframe ( it is a list shows the buy and sell operations of the strategy )
apple_signals = pd.concat([pd.DataFrame({"Price": apple.loc[apple["Signal"] == 1, "Close"],"Regime": apple.loc[apple["Signal"] == 1, "Regime"],"Signal": "Buy"}),pd.DataFrame({"Price": apple.loc[apple["Signal"] == -1, "Close"],"Regime": apple.loc[apple["Signal"] == -1, "Regime"],"Signal": "Sell"}),])
apple_signals.sort_index(inplace = True)
print(apple_signals.head())

回溯的买卖信号表单如下所示:

DateTimePriceRegimeSignal
2010-03-1531.9771421.0Buy
2010-06-1136.215714-1.0Sell
2010-06-1839.1528591.0Buy
2010-07-2237.002857-1.0Sell
2010-08-1635.3771440.0Buy

计算收益

我们称买入-卖出为一次完整的交易,那么利用回溯的买卖点表单,我们可以回测出均线交叉策略在历史数据上进行的每笔交易,以及每笔交易产生的收益。代码如下:

##### use the trading signal dataframe apple_signals to compute the profit
apple_long_profits = pd.DataFrame({"Price": apple_signals.loc[(apple_signals["Signal"] == "Buy") &apple_signals["Regime"] == 1, "Price"],"Profit": pd.Series(apple_signals["Price"] - apple_signals["Price"].shift(1)).loc[apple_signals.loc[(apple_signals["Signal"].shift(1) == "Buy") & (apple_signals["Regime"].shift(1) == 1)].index].tolist(),"End Date": apple_signals["Price"].loc[apple_signals.loc[(apple_signals["Signal"].shift(1) == "Buy") & (apple_signals["Regime"].shift(1) == 1)].index].index})
print(apple_long_profits.head())
draw_candle.pandas_candlestick_ohlc(apple, stick = 45, otherseries = ["20d", "50d"])

得到的交易清单如下:

DateTimeEnd DatePriceProfit
2010-03-152010-06-1131.9771424.238572
2010-06-182010-07-2239.152859-2.150002
2010-09-202011-03-3040.4614309.342857
2011-05-122011-05-2749.509998-1.308571
2011-07-142011-11-1751.1100012.805713

这里写图片描述
进行简单统计可以看到:
苹果股票在2010年1月1日至今这段时间内
如果我们从第一天买入股票,一直持有股票,最后一天卖出,获得的收益是每股124.02美元,收益率为412%
如果按照我们的策略进行买卖,总共完成了21笔交易,收益为美股82.35美元,收益率为273%

未完待续…

我们可以很直观的看到,得到的结果有点让人哭笑不得,显然按照移动均线交叉策略得到的结果还不如不使用任何策略来的靠谱。事实真的是这样吗?
此外,我们的策略还有很多漏洞,回测的过程也有许多问题,这些都将会在后面的工作中进行完善。

完整代码

import numpy as np
import pandas as pd
import pandas_datareader.data as web
import datetime
import time
import matplotlib.pyplot as plt
import pylab
import draw_candle##### get historical data of a stock
# the first time we get the stock data from the interface of yahoo
# but we may not want to do this step all the time, so we try to save it in .csv
#start = datetime.datetime(2016, 1, 1)
#end = datetime.date.today()
#apple = web.DataReader("AAPL", "yahoo", start, end)
#print(apple.head())
#apple.to_csv(path_or_buf='data_AAPL.csv')##### read the data from csv
apple=pd.read_csv(filepath_or_buffer='data_AAPL.csv')
#print(apple.head())
# note that some format(data type) of data we read from .csv has changed
# for example the attribute 'Date' should be the index of the dataframe, and the date type changed from datetime to string
# this changes would made our methods in draw_candle.py got trouble
# So we need to make the following changes
date_list = []
for i in range(len(apple)):date_str = apple['Date'][i]t = time.strptime(date_str, "%Y-%m-%d")temp_date = datetime.datetime(t[0], t[1], t[2])date_list.append(temp_date)
apple['DateTime'] = pd.Series(date_list,apple.index)
del apple['Date']
apple = apple.set_index('DateTime')##### we can visualize the data roughly
pylab.rcParams['figure.figsize'] = (10, 6)
#apple["Adj Close"].plot(grid=True)
#draw_candle.pandas_candlestick_ohlc(apple,stick = 'month')##### compute the moving average of the history data for different time span
# use np.round to cut data to a certain accuracy
apple["20d"] = np.round(apple["Close"].rolling(window = 20, center = False).mean(), 2)
apple["50d"] = np.round(apple["Close"].rolling(window = 50, center = False).mean(), 2)
apple["100d"] = np.round(apple["Close"].rolling(window = 200, center = False).mean(), 2)
#draw_candle.pandas_candlestick_ohlc(apple.loc['2016-01-04':'2017-09-01',:],stick='week',otherseries = ["20d", "50d", "100d"])##### compute the sub of the long time span moving average and the short one
# use regime to represent it
apple['20d-50d'] = apple['20d'] - apple['50d']
apple["Regime"] = np.where(apple['20d-50d'] > 0, 1, 0)
apple["Regime"] = np.where(apple['20d-50d'] < 0, -1, apple["Regime"])
regime_count = apple["Regime"].value_counts()
#print(regime_count)
#apple.loc['2017-01-01':'2017-09-01',"Regime"].plot(ylim = (-2,2)).axhline(y = 0, color = "black", lw = 2)
#apple["Regime"].plot(ylim = (-2,2)).axhline(y = 0, color = "black", lw = 2)##### use Regime to compute the trading signal
regime_orig = apple.ix[-1, "Regime"]
apple.ix[-1, "Regime"] = 0
apple["Signal"] = np.sign(apple["Regime"] - apple["Regime"].shift(1))
apple.ix[-1, "Regime"] = regime_orig##### build the trading signal dataframe ( it is a list shows the buy and sell operations of the strategy )
# the apple_signals looks like:
#                  Price  Regime Signal
# Date
# 2010-03-15   31.977142     1.0    Buy
# 2010-06-11   36.215714    -1.0   Sell
# 2010-06-18   39.152859     1.0    Buy
# 2010-07-22   37.002857    -1.0   Sell#print(apple.loc[apple["Signal"] == 1, "Close"])
#print(apple.loc[apple["Signal"] == -1, "Close"])
apple_signals = pd.concat([pd.DataFrame({"Price": apple.loc[apple["Signal"] == 1, "Close"],"Regime": apple.loc[apple["Signal"] == 1, "Regime"],"Signal": "Buy"}),pd.DataFrame({"Price": apple.loc[apple["Signal"] == -1, "Close"],"Regime": apple.loc[apple["Signal"] == -1, "Regime"],"Signal": "Sell"}),])
apple_signals.sort_index(inplace = True)##### use the trading signal dataframe apple_signals to compute the profit
# the apple_long_profits looks like:
#               End Date       Price     Profit
# Date
# 2010-03-15  2010-06-11   31.977142   4.238572
# 2010-06-18  2010-07-22   39.152859  -2.150002
# 2010-09-20  2011-03-30   40.461430   9.342857
apple_long_profits = pd.DataFrame({"Price": apple_signals.loc[(apple_signals["Signal"] == "Buy") &apple_signals["Regime"] == 1, "Price"],"Profit": pd.Series(apple_signals["Price"] - apple_signals["Price"].shift(1)).loc[apple_signals.loc[(apple_signals["Signal"].shift(1) == "Buy") & (apple_signals["Regime"].shift(1) == 1)].index].tolist(),"End Date": apple_signals["Price"].loc[apple_signals.loc[(apple_signals["Signal"].shift(1) == "Buy") & (apple_signals["Regime"].shift(1) == 1)].index].index})
#print(apple_long_profits)
#draw_candle.pandas_candlestick_ohlc(apple, stick = 45, otherseries = ["20d", "50d"])##### take a simple analysis
# compute a rough profit (don't consider fee of the deal)
rough_profit = apple_long_profits['Profit'].sum()
print(rough_profit)# compute the profit if we don't take any operation
# (take long position at the first day and sale it on the last day of the date)
no_operation_profit = apple['Close'][-1]-apple['Close'][0]
print(no_operation_profit)plt.show()

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/499518.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

STM32F412应用开发笔记之一:初识NUCLEO-F412ZG

&#xfeff;&#xfeff;今天终于收到了期待已久的NUCLEO-F412ZG&#xff0c;感谢电子发烧友论坛&#xff01; 近几年来基本都是在STM32平台上做一些设计开发工作。STM32F103、STM32F107、STM32F429等都应用过&#xff0c;但却从没有申请过试用。没想到这次申请居然能被选中&a…

STM32F412应用开发笔记之二:基本GPIO控制

&#xfeff;&#xfeff;NUCLEO-F412ZG板子上的元器件并没有完全焊接&#xff0c;除去ST-LINK部分和电源部分后&#xff0c;还有用一个USB主机接口&#xff0c;三个LED灯和两个按钮&#xff0c;不过很多功能引脚都已经引到了插针。查看原理图可发现&#xff0c;由原理图模块的…

1-3移动均线交叉策略2

第一阶段、一个简单策略入门量化投资 1-3移动均线交叉策略2 上一篇文章1-2 移动均线交叉策略1中我们最后提到&#xff1a; 如果我们从第一天买入股票&#xff0c;一直持有股票&#xff0c;最后一天卖出&#xff0c;获得的收益是每股124.02美元&#xff0c;收益率为412% 如果…

1-4移动均线交叉策略3

第一阶段、一个简单策略入门量化投资 1-4移动均线交叉策略3 上一文1-3移动均线交叉策略2中&#xff0c;我们得到的结果是令人失望的。但我们的探索还要继续。 我们知道&#xff0c;使用投资组合的方式进行分散投资是降低风险的好办法。尽管移动均线交叉策略的表现并不理想&a…

STM32学习及应用笔记一:SysTick定时器学习及应用

&#xfeff;&#xfeff; 这几年一直使用STM32的MCU&#xff0c;对ARM内核的SysTick计时器也经常使用&#xff0c;但几乎没有仔细了解过。最近正好要在移植一个新的操作系统时接触到了这块&#xff0c;据比较深入的了解了一下。 1、SysTick究竟是什么&#xff1f; 关于SysT…

使用Atom快速打造好用的Markdown编辑器

使用Atom快速打造好用的Markdown编辑器 Atom当前主流的跨平台的三大编辑器(Atom,sublime,vscode)之一 今天尝试了使用Atom来打造Markdown编辑器&#xff0c;快速上手且易用&#xff0c;墙裂推荐&#xff01; 下面直接进入正题&#xff0c;一步步介绍如何使用Atom快速打造好用…

PID控制器开发笔记之一:PID算法原理及基本实现

&#xfeff;&#xfeff; 在自动控制中&#xff0c;PID及其衍生出来的算法是应用最广的算法之一。各个做自动控制的厂家基本都有会实现这一经典算法。我们在做项目的过程中&#xff0c;也时常会遇到类似的需求&#xff0c;所以就想实现这一算法以适用于更多的应用场景。…

十分钟能学会的简单python爬虫

简单爬虫三步走&#xff0c;So easy~ 本文介绍一个使用python实现爬虫的超简单方法&#xff0c;精通爬虫挺难&#xff0c;但学会实现一个能满足简单需求的爬虫&#xff0c;只需10分钟&#xff0c;往下读吧~ 该方法不能用于带有反爬机制的页面&#xff0c;但对于我这样的非专业…

PID控制器开发笔记之二:积分分离PID控制器的实现

前面的文章中&#xff0c;我们已经讲述了PID控制器的实现&#xff0c;包括位置型PID控制器和增量型PID控制器。但这个实现只是最基本的实现&#xff0c;并没有考虑任何的干扰情况。在本节及后续的一些章节&#xff0c;我们就来讨论一下经典PID控制器的优化与改进。这一节我们首…

利用python实现短信和电话提醒功能

有时候&#xff0c;我们需要程序帮我们自动检测某些事件的发生 这个需求是广泛存在的 因此&#xff0c;这里整理了利用python实现短信和电话提醒功能的方法 主要需要完成以下4个步骤&#xff1a; - 安装核心库&#xff1a;twilio - 注册账号及配置 - 发送短信示例 - 电话…

PID控制器开发笔记之三:抗积分饱和PID控制器的实现

积分作用的引入是为了消除系统的静差&#xff0c;提高控制精度。但是如果一个系统总是存在统一个方向的偏差&#xff0c;就可能无限累加而进而饱和&#xff0c;极大影响系统性能。抗积分饱和就是用以解决这一问题的方法之一。这一节我们就来实现抗积分饱和的PID算法。 1、抗积…

如何获取STM32 MCU的唯一ID

前段时间由于应用需要对产品授权进行限制&#xff0c;所以研究了一下有关STM32 MCU的唯一ID的资料&#xff0c;并最终利用它实现了我们的目标。 1、基本描述 在STM32的全系列MCU中均有一个96位的唯一设备标识符。在ST的相关资料中&#xff0c;对其功能的描述有3各方面&#x…

SHA256算法原理详解

1. SHA256简介 SHA256是SHA-2下细分出的一种算法 SHA-2&#xff0c;名称来自于安全散列算法2&#xff08;英语&#xff1a;Secure Hash Algorithm 2&#xff09;的缩写&#xff0c;一种密码散列函数算法标准&#xff0c;由美国国家安全局研发&#xff0c;属于SHA算法之一&…

学习笔记:区块链概念入门

本文是100天区块链学习计划的第二篇学习笔记&#xff0c;其实就是按照阮一峰的网络日志-区块链入门教程的讲解进行的简单梳理。也是时间有点紧张的原因&#xff0c;相比于上一篇SHA256算法原理详解&#xff0c;个人感觉质量和原创程度明显下降。待对区块链有了更深的理解后&…

PID控制器开发笔记之四:梯形积分PID控制器的实现

从微积分的基本原理看&#xff0c;积分的实现是在无限细分的情况下进行的矩形加和计算。但是在离散状态下&#xff0c;时间间隔已经足够大&#xff0c;矩形积分在某些时候显得精度要低了一些&#xff0c;于是梯形积分被提出来以提升积分精度。 1、梯形积分基本思路 在PID控制…

SHA256 的C语言实现

前几天总结了SHA256的算法原理一文 SHA2系列的原理并不复杂&#xff0c;但是需要注意细节还是挺多的。不少中文博客贴出的代码都有错&#xff0c;这两天也踩了几个坑。 代码在这里&#xff01;&#xff01;&#xff01;SHA256的C Code 代码实现主要依照的这个git仓库crypto-…

信息摘要算法之一:MD5算法分析及实现

MD5即Message-DigestAlgorithm 5&#xff08;信息-摘要算法5&#xff09;&#xff0c;用于确保信息传输完整一致。是计算机广泛使用的杂凑算法之一&#xff08;又译摘要算法、哈希算法&#xff09;&#xff0c;主流编程语言普遍已有MD5实现。 1、MD5算法简介 MD5在90年代初由…

非对称加密概述

非对称加密概述 前言 在阅读《精通比特币》的过程中&#xff0c;我发现比特币系统中有两个重要的概念需要利用非对称加密技术&#xff1a; 比特币地址的生成 交易合法性的验证 因此&#xff0c;我用了几天时间学习了密码学基础知识&#xff0c;尤其是非对称加密技术的原理…

信息摘要算法之二:SHA1算法分析及实现

SHA算法&#xff0c;即安全散列算法&#xff08;Secure Hash Algorithm&#xff09;是一种与MD5同源的数据加密算法&#xff0c;该算法经过加密专家多年来的发展和改进已日益完善&#xff0c;现在已成为公认的最安全的散列算法之一&#xff0c;并被广泛使用。 1、概述 SHA算法…

2018数学建模A题的简单指导

之前写过一篇博客&#xff0c;介绍如何使用差分格式求解热传导方程 今天打开博客&#xff0c;突然发现评论区被这篇文章霸屏了 询问实验室的小伙伴才知&#xff0c;原来是被可爱的建模学子们攻占了 经过简单的了解&#xff0c;发现今年建模的A题的核心就是求解一个热传导方程…