跳转到根目录:知行合一:投资篇
已完成:
1、投资&技术
1.1.1 投资-编程基础-numpy
1.1.2 投资-编程基础-pandas
1.2 金融数据处理
1.3 金融数据可视化
2、投资方法论
2.1.1 预期年化收益率
2.1.2 一个关于y=ax+b的故事
2.1.3-数据标准化
2.1.4-相关性分析
2.2.1.1-一个关于定投的故(姿)事(势)
2.2.1.3-移动平均线
3、投资实证
[3.1 2023这一年] 被鸽
todo…
文章目录
- 1. 定义
- 2. 目标
- 3. 加载数据
- 4. 计算5日线值
- 5. 确定买卖点
- 6. 测算收益
- 7. 5日线绘图
- 8. 10日线绘图
- 9. k线图绘图
- 10. 完整代码&完整图表
- 11. 收益计算
1. 定义
移动平均线,Moving Average,简称MA,MA是用统计分析的方法,将一定时期内的证券价格(指数)加以平均,并把不同时间的平均值连接起来,形成一根MA,用以观察证券价格变动趋势的一种技术指标。
2. 目标
- 绘制一个k线图,也就是蜡烛图
- 计算5日均线值、10日均线值
- 在k线图上,绘制5日线和10日线图
- 在5日线上,绘制与10日线的交叉点(上穿、下穿时)
3. 加载数据
这次主要是绘图和数据处理,所以数据就使用现成的csv来做(之前的文章,有专门的数据获取方法,参考:《1.2-金融数据处理》)
import pandas as pd
import ssl # # URLError: <urlopen error [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: unable to get local issuer certificate (_ssl.c:1091)>
ssl._create_default_https_context = ssl._create_unverified_context
#导入pyecharts
from pyecharts.charts import *
from pyecharts import options as opts
from pyecharts.commons.utils import JsCode
df = pd.read_csv("https://gitee.com/kelvin11/public-resources/raw/master/SH510300.csv", parse_dates=['date'])
df.set_index('date', inplace=True)
解释1:
pd.read_csv("https://gitee.com/kelvin11/public-resources/raw/master/SH510300.csv", parse_dates=['date'])
是读取一个网络csv文件的内容,并且将其date列转换成日期类型。ssl._create_default_https_context = ssl._create_unverified_context
是解决https访问的时候的报错。
解释2:
df.set_index('date', inplace=True)
是将date列设为索引,并且将其从数据列中移除。移除的意思是,在遍历时,就无法通过df.loc[x, "date"]
这样取到date列的值了。
4. 计算5日线值
这个就比较简单了,直接通过pandas的rolling函数就行
import math
import pandas as pd
import ssl # URLError: <urlopen error [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: unable to get local issuer certificate (_ssl.c:1091)>
ssl._create_default_https_context = ssl._create_unverified_context
# 导入pyecharts
from pyecharts.charts import *
from pyecharts import options as opts
# 加载数据
df = pd.read_csv("https://gitee.com/kelvin11/public-resources/raw/master/SH510300.csv", parse_dates=['date'])
df.set_index('date', inplace=True)
# 计算5日线值、10日线值
df['ma5'] = df.close.rolling(5).mean()
df['ma10'] = df.close.rolling(20).mean()
5. 确定买卖点
什么时候买?什么时候卖?
当5日线上穿10日线时,是买点,当5日线下穿10日线时,是卖点。这个很好理解,代码实现在上面的基础上,继续操作:
# 导入数据分析和量化常用库
import math
import pandas as pd
import ssl # URLError: <urlopen error [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: unable to get local issuer certificate (_ssl.c:1091)>
ssl._create_default_https_context = ssl._create_unverified_context
# 导入pyecharts
from pyecharts.charts import *
from pyecharts import options as opts
# 加载数据
df = pd.read_csv("https://gitee.com/kelvin11/public-resources/raw/master/SH510300.csv", parse_dates=['date'])
df.set_index('date', inplace=True)
# 计算5日线值、10日线值
df['ma5'] = df.close.rolling(5).mean()
df['ma10'] = df.close.rolling(20).mean()
# df['ma20']=df.close.rolling(20).mean()
# df['macd'],df['macdsignal'],df['macdhist']=ta.MACD(df.close,fastperiod=12,slowperiod=26,signalperiod=9)
already_buy = False
# 遍历确定买卖点
for x in df.index:
if df.loc[x, "ma5"] > df.loc[x, "ma10"] and not already_buy:
df.loc[x, "买卖"] = '买'
already_buy = True
if df.loc[x, "ma5"] < df.loc[x, "ma10"] and already_buy:
df.loc[x, "买卖"] = '卖'
already_buy = False
6. 测算收益
如果我们严格按照上穿买入,下穿卖出,不考虑浮盈浮亏的情况下,这个策略,盈利性如何?
我们按照大约10000元作为交易金额,因为每次买入卖出最小的1手是100股,要做向上取整。
这里就只贴测算收益部分的代码:
# 测算收益
money = 10000.0 # 1个w左右的买卖金额
shares = 0 # 买入的股数
buy_price = 0 # 实际买入的金额
for x in df.index:
if df.loc[x, "买卖"] == '买':
buy_price = df.loc[x, "close"]
shares = math.floor(money / df.loc[x, "close"] / 100) * 100
real_buy_money = shares * buy_price
df.loc[x, "买入份额"] = shares
df.loc[x, "买入价格"] = buy_price
df.loc[x, "实际买入金额"] = real_buy_money
if df.loc[x, "买卖"] == '卖':
sell_price = df.loc[x, "close"]
real_sell_money = (sell_price - buy_price) * shares
df.loc[x, "卖出价格"] = sell_price
df.loc[x, "实际卖出金额"] = real_sell_money
df.loc[x, "收益"] = (sell_price - buy_price) * shares
# 冗余,以便在csv中直接看出卖出时,买入时候相关的要素信息
df.loc[x, "买入份额"] = shares
df.loc[x, "买入价格"] = buy_price
df.loc[x, "实际买入金额"] = real_buy_money
# 将买卖相关信息保存到csv,方便查看
df.to_csv('均线买卖.csv')
7. 5日线绘图
5日线图比较简单,照抄样例代码
# 绘制5日线折线图
line_ma5 = Line()
line_ma5.add_xaxis(df.index.strftime('%Y%m%d').tolist())
line_ma5.add_yaxis(
"MA5",
df['ma5'].tolist(),
is_smooth=True,
is_symbol_show=False,
label_opts=opts.LabelOpts(is_show=False)
)
我们还想更进一步,在5日线上,想标注一些买卖点,就好比如在我们常用的交易软件上的B点和S点
构造买卖点代码:
# 标记买卖点,方便在后面的绘图时,在折线图上把买卖点标注出来
buy_points = {}
sell_points = {}
for x in df.index:
if df.loc[x, "买卖"] == '买':
buy_points[x.strftime('%Y%m%d')] = df.loc[x, "close"]
if df.loc[x, "买卖"] == '卖':
sell_points[x.strftime('%Y%m%d')] = df.loc[x, "close"]
# 绘制5日线折线图
line_ma5 = Line()
line_ma5.add_xaxis(df.index.strftime('%Y%m%d').tolist())
line_ma5.add_yaxis(
"MA5",
df['ma5'].tolist(),
is_smooth=True,
is_symbol_show=False,
label_opts=opts.LabelOpts(is_show=False),
markpoint_opts=opts.MarkPointOpts(
data=[
# 买点标注
*[
opts.MarkPointItem(
coord=[day, value],
value='B', # value
name=f"Buy at {day}",
itemstyle_opts=opts.ItemStyleOpts(color="green"),
)
for day, value in buy_points.items()
],
# 卖点标注
*[
opts.MarkPointItem(
coord=[day, value],
value='S',
name=f"Sell at {day}",
itemstyle_opts=opts.ItemStyleOpts(color="red"),
)
for day, value in sell_points.items()
],
]
)
)
8. 10日线绘图
这个就没难度了
# 绘制10日线折线图
line_ma10 = Line()
line_ma10.add_xaxis(df.index.strftime('%Y%m%d').tolist())
line_ma10.add_yaxis(
"MA10",
df['ma10'].tolist(),
is_smooth=True,
is_symbol_show=False,
label_opts=opts.LabelOpts(is_show=False)
)
9. k线图绘图
这个就是pyecharts比较强大的地方了,参考其绘制k线的文档:k线图
包含元素:
- 红绿柱状图
- K线图底部滑块,可以缩放对应的区间数据
- 对于一个时间区间可以进行标注(本例标注了:
opts.MarkAreaItem(name="14-15牛市", x=("20140624", "20150612"))
) - 标注了期间内最大max最小值min均值average辅助线
# 绘制k线图
kline = (Kline()
.add_xaxis(df.index.strftime('%Y%m%d').tolist()) # x轴数据
# y轴数据,默认open、close、high、low,转为list格式
.add_yaxis(series_name="",
y_axis=df[['open', 'close', 'low', 'high']].values.tolist(),
itemstyle_opts=opts.ItemStyleOpts(
color="red", # 阳线红色
color0="green", # 阴线绿色
border_color="red",
border_color0="green", ),
# markpoint_opts=opts.MarkPointOpts(data=[#添加标记符
# opts.MarkPointItem(type_='max', name='最大值'),
# opts.MarkPointItem(type_='min', name='最小值'),]),
# 添加辅助性,如某期间内最大max最小值min均值average
markline_opts=opts.MarkLineOpts(
data=[opts.MarkLineItem(type_="average",
value_dim="close")], ), )
.set_global_opts(
datazoom_opts=[opts.DataZoomOpts()], # 滑动模块选择
)
.set_series_opts(
markarea_opts=opts.MarkAreaOpts( # 标记区域配置项
data=[
opts.MarkAreaItem(name="14-15牛市", x=("20140624", "20150612")),
], ))
)
# 在k线图上叠加5日线折线图
kline.overlap(line_ma5)
# 在k线图上叠加10日线折线图
kline.overlap(line_ma10)
# 在jupyter notebook上直接渲染
kline.render_notebook()
# 如果是在pycharm里,使用:kline.render("k线+移动均线+买卖点标记.html")这样生成html查看
具体展示的结果,看下一节“完整代码&完整图表”
10. 完整代码&完整图表
直接上干货,总共就145行代码,解决问题。
# 导入数据分析和量化常用库
import math
import pandas as pd
import ssl # URLError: <urlopen error [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: unable to get local issuer certificate (_ssl.c:1091)>
ssl._create_default_https_context = ssl._create_unverified_context
# 导入pyecharts
from pyecharts.charts import *
from pyecharts import options as opts
# 加载数据
df = pd.read_csv("https://gitee.com/kelvin11/public-resources/raw/master/SH510300.csv", parse_dates=['date'])
df.set_index('date', inplace=True)
# 计算5日线值、10日线值
df['ma5'] = df.close.rolling(5).mean()
df['ma10'] = df.close.rolling(20).mean()
# df['ma20']=df.close.rolling(20).mean()
# df['macd'],df['macdsignal'],df['macdhist']=ta.MACD(df.close,fastperiod=12,slowperiod=26,signalperiod=9)
already_buy = False
# 遍历确定买卖点
for x in df.index:
if df.loc[x, "ma5"] > df.loc[x, "ma10"] and not already_buy:
df.loc[x, "买卖"] = '买'
already_buy = True
if df.loc[x, "ma5"] < df.loc[x, "ma10"] and already_buy:
df.loc[x, "买卖"] = '卖'
already_buy = False
# 测算收益
money = 10000.0 # 1个w左右的买卖金额
shares = 0 # 买入的股数
buy_price = 0 # 实际买入的金额
for x in df.index:
if df.loc[x, "买卖"] == '买':
buy_price = df.loc[x, "close"]
shares = math.floor(money / df.loc[x, "close"] / 100) * 100
real_buy_money = shares * buy_price
df.loc[x, "买入份额"] = shares
df.loc[x, "买入价格"] = buy_price
df.loc[x, "实际买入金额"] = real_buy_money
if df.loc[x, "买卖"] == '卖':
sell_price = df.loc[x, "close"]
real_sell_money = (sell_price - buy_price) * shares
df.loc[x, "卖出价格"] = sell_price
df.loc[x, "实际卖出金额"] = real_sell_money
df.loc[x, "收益"] = (sell_price - buy_price) * shares
# 冗余,以便在csv中直接看出卖出时,买入时候相关的要素信息
df.loc[x, "买入份额"] = shares
df.loc[x, "买入价格"] = buy_price
df.loc[x, "实际买入金额"] = real_buy_money
# 将买卖相关信息保存到csv,方便查看
df.to_csv('均线买卖.csv')
# 标记买卖点,方便在后面的绘图时,在折线图上把买卖点标注出来
buy_points = {}
sell_points = {}
for x in df.index:
if df.loc[x, "买卖"] == '买':
buy_points[x.strftime('%Y%m%d')] = df.loc[x, "close"]
if df.loc[x, "买卖"] == '卖':
sell_points[x.strftime('%Y%m%d')] = df.loc[x, "close"]
# 绘制5日线折线图
line_ma5 = Line()
line_ma5.add_xaxis(df.index.strftime('%Y%m%d').tolist())
line_ma5.add_yaxis(
"MA5",
df['ma5'].tolist(),
is_smooth=True,
is_symbol_show=False,
label_opts=opts.LabelOpts(is_show=False),
markpoint_opts=opts.MarkPointOpts(
data=[
# 买点标注
*[
opts.MarkPointItem(
coord=[day, value],
value='B', # value
name=f"Buy at {day}",
itemstyle_opts=opts.ItemStyleOpts(color="green"),
)
for day, value in buy_points.items()
],
# 卖点标注
*[
opts.MarkPointItem(
coord=[day, value],
value='S',
name=f"Sell at {day}",
itemstyle_opts=opts.ItemStyleOpts(color="red"),
)
for day, value in sell_points.items()
],
]
)
)
# 绘制10日线折线图
line_ma10 = Line()
line_ma10.add_xaxis(df.index.strftime('%Y%m%d').tolist())
line_ma10.add_yaxis(
"MA10",
df['ma10'].tolist(),
is_smooth=True,
is_symbol_show=False,
label_opts=opts.LabelOpts(is_show=False)
)
# 绘制k线图
kline = (Kline()
.add_xaxis(df.index.strftime('%Y%m%d').tolist()) # x轴数据
# y轴数据,默认open、close、high、low,转为list格式
.add_yaxis(series_name="",
y_axis=df[['open', 'close', 'low', 'high']].values.tolist(),
itemstyle_opts=opts.ItemStyleOpts(
color="red", # 阳线红色
color0="green", # 阴线绿色
border_color="red",
border_color0="green", ),
# markpoint_opts=opts.MarkPointOpts(data=[#添加标记符
# opts.MarkPointItem(type_='max', name='最大值'),
# opts.MarkPointItem(type_='min', name='最小值'),]),
# 添加辅助性,如某期间内最大max最小值min均值average
markline_opts=opts.MarkLineOpts(
data=[opts.MarkLineItem(type_="average",
value_dim="close")], ), )
.set_global_opts(
datazoom_opts=[opts.DataZoomOpts()], # 滑动模块选择
)
.set_series_opts(
markarea_opts=opts.MarkAreaOpts( # 标记区域配置项
data=[
opts.MarkAreaItem(name="14-15牛市", x=("20140624", "20150612")),
], ))
)
# 在k线图上叠加5日线折线图
kline.overlap(line_ma5)
# 在k线图上叠加10日线折线图
kline.overlap(line_ma10)
# 在jupyter notebook上直接渲染
kline.render_notebook()
# 如果是在pycharm里,使用:kline.render("k线+移动均线+买卖点标记.html")这样生成html查看
下图,能看出所有要素,由于买卖点过于集中,看起来就不是很美观,但是,可以通过拖动下面的滑块,来看更精准的图。
拖动滑块,看具体时间段内的情况,可以非常清晰的看到5日线、10日线、买卖点、区间最大最小值均值:
11. 收益计算
最后多说一点,如果无脑按照这个来测算,最终的收益是:4167.6元(2012/5/28 ~ 2023/11/24),真的是很不~可观。
这其实很正常,因为每次的持有时间都很短,很多时候是亏本卖出。
想要调优策略,还是得加入自己的其他主观策略,无脑使用注定是不行的。