摘要:金融领域一向都是与数学和统计高度相关的行业,今天数学建模已经成为金融行业的发展动力和竞争力表现,人才需求旺盛。
金融领域一向都是与数学和统计高度相关的行业,今天数学建模已经成为金融行业的发展动力和竞争力表现,人才需求旺盛。特别是近年来大数据和计算机技术的发展,算法成为投资领域的重要决策手段之一,算法交易也成为重要的股票交易技术,特别是高频交易(HFT),量化投资等依赖机器算法的模型越来越流行。
恰巧看到一篇国外博客介绍Python在股票投资的应用,俺模仿看看如何玩玩股票投资组合的模型建模方法。第一讲先讲讲如何获取数据和可视化。后面一篇文章讲如何进行投资组合建模。
第一部分先介绍如何获取股票数据和可视化分析,移动平均的分析。
第一步:获取股票数据
我们需要安装一个python包:pip install pandas_datareader
包的相关说明:https://pandas-datareader.readthedocs.io/en/latest/
包可用通过API直接获取yahoo财经,Google 财经,world bank等数据接口提供的股票数据,这里我们用雅虎财经——yahoo finance的股票接口数据。
假设我们要获得沪市贵州茅台(600519.SS)——才有股票代码加沪深SS或SZ。
定义了股票开始日期和截止日期(系统今日时间)后
这样就获得了2010-1-1至2016-12-13日(今天)的贵州茅台股票基本数据。
可用看到很快就得到了沪市A股贵州茅台的近7年的股价数据。
接下来我们进行一系列可视化图表分析
这里用到了标准的matplotlib库,将输出结果呈现在Jupther上。
对于股票类型数据,High、Low、Open、Close、Adj Close如何在一张图上表现,最常用的叫阴阳烛图candlestick_ohlc。
为了阅读方便,画阴阳烛图的Python函数代码在文章最后...
pandas_candlestick_ohlc(maotai)
如果是多只股票的可视化如何表现呢?我们再多抓几只股票数据(同一周期)
我们增加同仁堂600085.SS和全聚德002186.SZ两只股票
看看走势图
我们发现因为三只股票的股价不同,坐标尺度不统一造成可视化不清晰。考量不同股票的股价不同,坐标标度有显著尺度差异,可用考虑用双轴标度可视化。
坐标尺度考虑是一方面,我们也可以考虑采用基期2010-1-4日股价作为基点进行对标或标准化股票指数化。
可视化趋势图
从趋势上看,从2010年第一个交易日开始,这三只股票基本上都是增长趋势,特别是同仁堂股价增长变动较大。
我们还可以计算各种股价的增长或变化,用:
或者:
我先展示用log变化:
最后,在可视化部分我们来看移动平均的趋势图。
在Python中实现q-day的移动平均(moving average)是比较方便的
我们下面分别指定20d、50d和200d的窗口期分析移动平均的走势图
至此我们完成了沪市或深市A股选择的股票交易数据下载,并采用各种可视化和标准化方法,以及给出了移动平均的趋势图的可视化。
当然这不是我玩的目的,只是告诉大家获取数据的方便性,以及Python的各种包的易用性,如果将股票数据下载后导入Tableau或其他软件也可以进行各种分析,特别是R语言有很多股票分析模型。
其实本篇文章的重点是接下来我要描述如何在固定投资金额比如100万,预期收益率10%,止损率20%的条件下如何进行多只股票组合投资的buy-sell模型。
如果您也在玩的话,可以先看看移动平均曲线,以及不同周期移动平均的交叉点的含义。
说实话,俺对股票也是一窍不通的,多头和空头,长线和短线,看空看多的投资策略都影响模型的建立和落实。
大家可以拷贝这段代码:pandas_candlestick_ohlc(maotai)
from matplotlib.dates import DateFormatter, WeekdayLocator, DayLocator, MONDAY
from matplotlib.finance import candlestick_ohlc
def pandas_candlestick_ohlc(dat, stick = "day", otherseries = None):
"""
:param dat: pandas DataFrame object with datetime64 index, and float columns "Open", "High", "Low", and "Close", likely created via DataReader from "yahoo"
:param stick: A string or number indicating the period of time covered by a single candlestick. Valid string inputs include "day", "week", "month", and "year", ("day" default), and any numeric input indicates the number of trading days included in a period
:param otherseries: An iterable that will be coerced into a list, containing the columns of dat that hold other series to be plotted as lines
This will show a Japanese candlestick plot for stock data stored in dat, also plotting other series if passed.
"""
mondays = WeekdayLocator(MONDAY) # major ticks on the mondays
alldays = DayLocator() # minor ticks on the days
dayFormatter = DateFormatter(%d) # e.g., 12
# Create a new DataFrame which includes OHLC data for each period specified by stick input
transdat = dat.loc[:,["Open", "High", "Low", "Close"]]
if (type(stick) == str):
if stick == "day":
plotdat = transdat
stick = 1 # Used for plotting
elif stick in ["week", "month", "year"]:
if stick == "week":
transdat["week"] = pd.to_datetime(transdat.index).map(lambda x: x.isocalendar()[1]) # Identify weeks
elif stick == "month":
transdat["month"] = pd.to_datetime(transdat.index).map(lambda x: x.month) # Identify months
transdat["year"] = pd.to_datetime(transdat.index).map(lambda x: x.isocalendar()[0]) # Identify years
grouped = transdat.groupby(list(set(["year",stick]))) # Group by year and other appropriate variable
plotdat = pd.DataFrame(,
index = [group.index[0]]))
else:
raise ValueError(Valid inputs to argument "stick" include the strings "day", "week", "month", "year", or a positive integer)
# Set plot parameters, including the axis object ax used for plotting
fig, ax = plt.subplots()
fig.subplots_adjust(bottom=0.2)
if plotdat.index[-1] - plotdat.index[0] < pd.Timedelta(730 days):
weekFormatter = DateFormatter(%b %d) # e.g., Jan 12
ax.xaxis.set_major_locator(mondays)
ax.xaxis.set_minor_locator(alldays)
else:
weekFormatter = DateFormatter(%b %d, %Y)
ax.xaxis.set_major_formatter(weekFormatter)
ax.grid(True)
# Create the candelstick chart
candlestick_ohlc(ax, list(zip(list(date2num(plotdat.index.tolist())), plotdat["Open"].tolist(), plotdat["High"].tolist(),
plotdat["Low"].tolist(), plotdat["Close"].tolist())),
colorup = "black", colordown = "red", width = stick * .4)
# Plot other series (such as moving averages) as lines
if otherseries != None:
if type(otherseries) != list:
otherseries = [otherseries]
dat.loc[:,otherseries].plot(ax = ax, lw = 1.3, grid = True)
ax.xaxis_date()
ax.autoscale_view()
plt.setp(plt.gca().get_xticklabels(), rotation=45, horizontalalignment=right)
plt.show()
pandas_candlestick_ohlc(maotai)