2.2.1.3-移动平均线(python画k线、均线、5日线、买卖点图、python均线策略)

跳转到根目录:知行合一:投资篇

已完成:
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. 定义

移动平均线,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),真的是很不~可观。

这其实很正常,因为每次的持有时间都很短,很多时候是亏本卖出。

想要调优策略,还是得加入自己的其他主观策略,无脑使用注定是不行的。

  • 7
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
要在python股票k线图并添加均线,可以按照以下步骤进行操作: 1. 导入必要的库:使用`import`语句导入需要的库,例如`import matplotlib.pyplot as plt`和`import mpl_finance as mpf`。 2. 准备数据:将股票的历史数据存储在一个数据框中,确保数据框包含日期、开盘价、最高价、最低价和收盘价等必要的列。 3. 计算均线数据:使用`rolling`函数和`mean`函数计算5日均线和10日均线的数据,并将结果存储在数据框的新列中。例如,使用以下代码计算5日均线和10日均线: ``` df['M5'] = df['close'].rolling(5).mean() # 5日均线 df['M10'] = df['close'].rolling(10).mean() # 10日均线 ``` 4. 创建布和子图:使用`plt.subplots`函数创建布和子图,并设置布的大小。例如,使用以下代码创建一个大小为15x6的布和子图: ``` fig, ax = plt.subplots(figsize=(15, 6)) ``` 5. 绘制k线图:使用`mpf.candlestick_ochl`函数绘制k线图,传入子图名称、股票历史数据、k线柱的宽度、涨跌颜色和柱形透明度等参数。例如,使用以下代码绘制k线图: ``` mpf.candlestick_ochl(ax, df_arr, width=0.6, colorup='r', colordown='g', alpha=1) ``` 6. 添加均线图:使用`plt.plot`函数在同一子图中绘制均线图。例如,使用以下代码绘制5日均线和10日均线: ``` plt.plot(df_arr[:, 0], df['M5']) # 绘制5日均线 plt.plot(df_arr[:, 0], df['M10']) # 绘制10日均线 ``` 7. 添加标题和坐标轴标签:使用`plt.title`、`plt.xlabel`和`plt.ylabel`函数分别设置标题、x轴标签和y轴标签。例如,使用以下代码添加标题和标签: ``` plt.title('股票名称') # 设置标题 plt.xlabel('日期') # 设置x轴标签 plt.ylabel('价格') # 设置y轴标签 ``` 8. 设置刻度格式:使用`ax.xaxis_date`函数将x轴刻度设置为常规日期格式。 9. 显示图像:使用`plt.show`函数显示绘制的图像。 请注意,上述步骤中的变量名和参数值应根据实际情况进行调整。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* *3* [python绘制股票k线图](https://blog.csdn.net/hjhlln/article/details/127282449)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 100%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值