Bohrium
robot
新建

空间站广场

论文
Notebooks
比赛
课程
Apps
我的主页
我的Notebooks
我的论文库
我的足迹

我的工作空间

任务
节点
文件
数据集
镜像
项目
数据库
公开
快速上手!我在Bohrium炒股票(一)
量化交易
量化交易
cyrus
发布于 2023-10-31
推荐镜像 :Basic Image:bohrium-notebook:2023-04-07
推荐机型 :c2_m4_cpu
赞 11
2
一、数据
二、K线图
三、计算MACD指标
四、只看MACD,我能赚多少钱?

相信每一个学过一些机器学习、数据分析的同学都有过一场“股神”梦:

如果能发现股票价格变化的规律,岂不是直接财富自由了?

这同时也是每个量化交易从事者的梦。然而,对于绝大部分同学,是不是连从哪里获得股票的数据都不清楚?

今天就让我们一起看看,从零开始用机器学习来炒股!

当然,最重要的话说在前面:

【股市有风险,投资需谨慎!】

代码
文本

一、数据

获取数据是所有机器学习的第一步。那么,海量的交易数据从哪里得到呢?

幸运的是,开源工具“akshare”为我们提供了一个快速获取历史交易数据的接口。

让我们一起看看怎么使用吧!

首先通过 pip 安装 akshare,运行时间大约在1分钟左右:

代码
文本
[1]
%%bash
# < 1min
pip install akshare -i http://mirrors.aliyun.com/pypi/simple/ --trusted-host=mirrors.aliyun.com --upgrade > /tmp/piplog
WARNING: Running pip as the 'root' user can result in broken permissions and conflicting behaviour with the system package manager. It is recommended to use a virtual environment instead: https://pip.pypa.io/warnings/venv
代码
文本

安装以后,就可以直接在Python中进行调用了。akshare使用pandas的dataframe进行数据管理。让我们首先看看“酱香科技”贵州茅台(600519)的表现吧!

代码
文本
[2]
target = "600519"
# MaoTai: 600519
# WuLiangYe: 000858
代码
文本
[3]
import akshare as ak
stock_zh_a_daily_df = ak.stock_zh_a_hist(symbol=target, period="daily", start_date="20000101", end_date='20231231', adjust="")
print(stock_zh_a_daily_df)
/opt/conda/lib/python3.8/site-packages/akshare/__init__.py:2586: UserWarning: 为了支持更多特性,请将 Pandas 升级到 2.1.0 及以上版本!
  warnings.warn(
/opt/conda/lib/python3.8/site-packages/akshare/__init__.py:2591: UserWarning: 为了支持更多特性,请将 Python 升级到 3.9 及以上版本!
  warnings.warn(
              日期       开盘       收盘       最高       最低     成交量           成交额  \
0     2001-08-27    34.51    35.55    37.78    32.85  406318  1.410347e+09   
1     2001-08-28    34.99    36.86    37.00    34.61  129647  4.634630e+08   
2     2001-08-29    36.98    36.38    37.00    36.10   53252  1.946890e+08   
3     2001-08-30    36.28    37.10    37.51    36.00   48013  1.775580e+08   
4     2001-08-31    37.15    37.01    37.62    36.80   23231  8.623100e+07   
...          ...      ...      ...      ...      ...     ...           ...   
5301  2023-10-25  1670.11  1677.50  1698.00  1667.02   36179  6.075417e+09   
5302  2023-10-26  1667.00  1672.23  1688.00  1662.01   22386  3.741419e+09   
5303  2023-10-27  1664.00  1676.71  1691.88  1660.60   34262  5.754795e+09   
5304  2023-10-30  1669.00  1681.00  1688.88  1669.00   24086  4.050573e+09   
5305  2023-10-31  1680.00  1684.58  1690.00  1667.85   19859  3.335805e+09   

         振幅    涨跌幅    涨跌额    换手率  
0     15.71  13.25   4.16  56.83  
1      6.72   3.68   1.31  18.13  
2      2.44  -1.30  -0.48   7.45  
3      4.15   1.98   0.72   6.72  
4      2.21  -0.24  -0.09   3.25  
...     ...    ...    ...    ...  
5301   1.89   2.10  34.55   0.29  
5302   1.55  -0.31  -5.27   0.18  
5303   1.87   0.27   4.48   0.27  
5304   1.19   0.26   4.29   0.19  
5305   1.32   0.21   3.58   0.16  

[5306 rows x 11 columns]
代码
文本

可以看到,包括最新日期的每日交易数据都可以直接获取,数据内容包括每日交易的开盘、收盘、最高、最低价格,以及其他更丰富的指标。

如果你觉得每日数据不够爽,那还可以通过下面的方式获得每分钟的交易数据(对于5分钟周期,目前似乎只能追溯近两个月左右的数据):

代码
文本
[4]
stock_zh_a_5min_df = ak.stock_zh_a_hist_min_em(symbol="600519", period=5, start_date="20200101 09:30", end_date='20231231 15:00', adjust="")
print(stock_zh_a_5min_df)
                       时间       开盘       收盘       最高       最低   涨跌幅    涨跌额  \
0     2023-09-08 09:35:00  1834.94  1827.88  1834.94  1827.00 -0.55 -10.12   
1     2023-09-08 09:40:00  1828.00  1829.11  1833.77  1828.00  0.07   1.23   
2     2023-09-08 09:45:00  1829.03  1829.19  1831.13  1828.00  0.00   0.08   
3     2023-09-08 09:50:00  1829.00  1828.00  1832.23  1828.00 -0.07  -1.19   
4     2023-09-08 09:55:00  1828.00  1827.80  1830.00  1827.78 -0.01  -0.20   
...                   ...      ...      ...      ...      ...   ...    ...   
1531  2023-10-31 14:40:00  1688.50  1688.86  1689.80  1686.00  0.07   1.25   
1532  2023-10-31 14:45:00  1689.08  1688.99  1690.00  1688.16  0.01   0.13   
1533  2023-10-31 14:50:00  1689.08  1688.00  1689.96  1687.23 -0.06  -0.99   
1534  2023-10-31 14:55:00  1688.00  1687.72  1688.88  1686.00 -0.02  -0.28   
1535  2023-10-31 15:00:00  1687.43  1684.58  1688.10  1684.58 -0.19  -3.14   

      成交量          成交额    振幅   换手率  
0     971  177764381.0  0.43  0.01  
1     467   85460104.0  0.32  0.00  
2     393   71918217.0  0.17  0.00  
3     488   89271561.0  0.23  0.00  
4     277   50643615.0  0.12  0.00  
...   ...          ...   ...   ...  
1531  878  148293264.0  0.23  0.01  
1532  614  103743462.0  0.11  0.00  
1533  654  110457987.0  0.16  0.01  
1534  613  103394423.0  0.17  0.00  
1535  818  137861172.0  0.21  0.01  

[1536 rows x 11 columns]
代码
文本

二、K线图

可视化是处理数据的第一步。手写一个画K线的脚本可能比较困难,但我们可以通过mplfinance来快速实现一波。

首先pip安装一下mplfinance包(根据名称来看,是基于matplotlib开发的)

代码
文本
[5]
%%bash
pip install mplfinance > /tmp/piplog2
WARNING: Running pip as the 'root' user can result in broken permissions and conflicting behaviour with the system package manager. It is recommended to use a virtual environment instead: https://pip.pypa.io/warnings/venv
代码
文本

而后,我们画一下2023年上半年茅台的K线图

代码
文本
[6]
import akshare as ak
import mplfinance as mpf # Please install mplfinance as follows: pip install mplfinance
import datetime
import pandas as pd

df = stock_zh_a_daily_df[["日期", "开盘", "最高", "最低", "收盘", "成交量"]]
df.set_index("日期", inplace=True)
df.index = pd.DatetimeIndex(df.index)
df.index.name = "Date"
df.columns = ["Open", "High", "Low", "Close", "Volume"]
df = df["2023-01-01": "2023-06-30"]
mpf.plot(df, type='candle', mav=(5, 10, 20), volume=True, show_nontrading=False)
代码
文本

可以看到,经过简单的dataframe处理,预制的画图脚本可以很快的画出K线图,以及对应的5/10/20日均线。

代码
文本

三、计算MACD指标

MACD是股票交易中常用的指标之一,有“指标之王”的称呼。目前常用的MACD指标一般选取参数(12,26,9)。为计算MACD,应先行计算出快速(12日)移动平均值与慢速(26日)移动平均值。以这两个数值作为测量两者(快速与慢速线)间的“差离值”依据。所谓“差离值”(DIF),即12日EMA数值减去26日EMA数值。基于DIF,我们可以进一步计算DEA指标,即DIF指标的指数平均以进行综合的判断。

我们采用pandas自带的指数平均函数进行相关的计算。

代码
文本
[7]
def macd(close): # 输入收盘价
ema12 = close.ewm(span=12, adjust=False).mean()
ema26 = close.ewm(span=26, adjust=False).mean()
dif = ema12 - ema26
dea = dif.ewm(span=9, adjust=False).mean()
histogram = dif - dea
return ema12, ema26, histogram, dif, dea
代码
文本
[8]
e12, e26, hg, dif, dea = macd(df.Close)
代码
文本

为了直观的使用这一指标,我们将MACD画在前面生成的K线图上:

代码
文本
[9]
apds = [
mpf.make_addplot(e12, color="lime"),
mpf.make_addplot(e26, color="cyan"),
mpf.make_addplot(hg.clip(lower=0.), type="bar", color="red", width=0.5, panel=1, secondary_y=False),
mpf.make_addplot(hg.clip(upper=0.), type="bar", color="green", width=0.5, panel=1, secondary_y=False),
mpf.make_addplot(dif, color="gray", panel=1, secondary_y=True),
mpf.make_addplot(dea, color="purple", panel=1, secondary_y=True),
]

sty = mpf.make_mpf_style(base_mpf_style="classic")
mpf.plot(df, type='candle', addplot=apds, style=sty, volume=True, volume_panel=2, panel_ratios=(6,3,1), show_nontrading=False)
代码
文本

由此,我们成功生成了MACD的指标。

可以看到,在几次大的涨幅时,灰色的DIF线基本都向上穿过紫色的DEA线,即MACD金叉出现。

那么,如何使用MACD指标呢?百度百科是这么说的——

  1. MACD金叉:DIF由下向上突破 DEA,为买入信号。

  2. MACD死叉:DIF由上向下突破 DEA,为卖出信号。

  3. MACD 绿转红:MACD 值由负变正,市场由空头转为多头。

  4. MACD 红转绿:MACD 值由正变负,市场由多头转为空头。

  5. DIFF 与 DEA 均为正值,即都在零轴线以上时,大势属多头市场,DIFF 向上突破 DEA,可作买入信号。

  6. DIFF 与 DEA 均为负值,即都在零轴线以下时,大势属空头市场,DIFF 向下跌破 DEA,可作卖出信号。

  7. 当 DEA 线与 K 线趋势发生背离时为反转信号。

代码
文本

四、只看MACD,我能赚多少钱?

说了这么多,只用MACD指标,我们能赚到多少钱呢?

我们首先做一个非常朴素的假定:市场只有茅台一只股票,我们的目标是从价格波动中尽可能地套利,且能做的操作只有全买/全卖,每次购买的金额相同,期待获得最大的收益率。

下面我们定义一个最简单的交易策略:在MACD金叉出现时,我们进行股票购入,在死叉出现时,我们进行卖出。为简化模型,我们以每日的收盘价进行买入/卖出。

代码
文本
[10]
buy_price = buy_date = None
results = []
for t, i, p in zip(df.index, hg, df.Close):
if i > 0 and buy_price is None: # MACD绿转红
buy_price = p
buy_date = t
print(t.strftime('%Y-%m-%d'),
f"buy at {p:.2f} rmb.")
elif i < 0 and buy_price is not None: # MACD红转绿
y = (p - buy_price) / buy_price
print(t.strftime('%Y-%m-%d'),
f"sell at {p:.2f} rmb, yield {100*y:.2f}% in {(t - buy_date).days:d} days")
buy_price = buy_date = None
results.append(y)

print(f"Yield {sum(results)*100:.2f}% in half a year.")

2023-01-05 buy  at 1801.00 rmb.
2023-02-01 sell at 1844.97 rmb, yield 2.44% in 27 days
2023-02-21 buy  at 1867.00 rmb.
2023-02-22 sell at 1836.00 rmb, yield -1.66% in 1 days
2023-03-23 buy  at 1774.86 rmb.
2023-04-11 sell at 1745.50 rmb, yield -1.65% in 19 days
2023-04-27 buy  at 1757.92 rmb.
2023-05-10 sell at 1725.00 rmb, yield -1.87% in 13 days
2023-05-22 buy  at 1746.00 rmb.
2023-05-26 sell at 1690.56 rmb, yield -3.18% in 4 days
2023-06-09 buy  at 1666.00 rmb.
2023-06-30 sell at 1691.00 rmb, yield 1.50% in 21 days
Yield -4.42% in half a year.
代码
文本

可以看到,即便肉眼看到金叉/死叉出现的时机和股票涨跌有相关性,但严格按照这个策略进行交易反而亏掉了约4%。

对比K线图,我们发现,其中的原因是金叉/死叉出现的时机往往存在滞后性,往往涨幅都跌完了,死叉才出现。

因此,我们从更高阶的指标出发进行交易:一旦DIF开始从下至上接近DEA,我们就买入;一旦从上至下接近DEA,我们就卖出。

试试新的策略:

代码
文本
[11]
buy_price = buy_date = None
results = []
prev_i = None
for t, i, p in zip(df.index, hg, df.Close):
if prev_i is None:
pass
elif i - prev_i > 0.0 and buy_price is None: # MACD有上升趋势
buy_price = p
buy_date = t
print(t.strftime('%Y-%m-%d'),
f"buy at {p:.2f} rmb.")
elif i - prev_i < -0.0 and buy_price is not None: # MACD有下降趋势
y = (p - buy_price) / buy_price
print(t.strftime('%Y-%m-%d'),
f"sell at {p:.2f} rmb, yield {100*y:.2f}% in {(t - buy_date).days:d} days.")
buy_price = buy_date = None
results.append(y)
prev_i = i

print(f"Yield {sum(results)*100:.2f}% in half a year.")

2023-01-05 buy  at 1801.00 rmb.
2023-01-12 sell at 1834.00 rmb, yield 1.83% in 7 days.
2023-01-13 buy  at 1887.00 rmb.
2023-01-17 sell at 1908.00 rmb, yield 1.11% in 4 days.
2023-02-09 buy  at 1818.00 rmb.
2023-02-17 sell at 1820.78 rmb, yield 0.15% in 8 days.
2023-02-20 buy  at 1875.00 rmb.
2023-02-22 sell at 1836.00 rmb, yield -2.08% in 2 days.
2023-02-28 buy  at 1813.74 rmb.
2023-03-03 sell at 1818.04 rmb, yield 0.24% in 3 days.
2023-03-13 buy  at 1762.00 rmb.
2023-03-20 sell at 1729.60 rmb, yield -1.84% in 7 days.
2023-03-21 buy  at 1775.00 rmb.
2023-04-03 sell at 1802.07 rmb, yield 1.53% in 13 days.
2023-04-04 buy  at 1814.59 rmb.
2023-04-06 sell at 1796.96 rmb, yield -0.97% in 2 days.
2023-04-17 buy  at 1753.00 rmb.
2023-04-21 sell at 1725.47 rmb, yield -1.57% in 4 days.
2023-04-25 buy  at 1730.38 rmb.
2023-05-08 sell at 1720.52 rmb, yield -0.57% in 13 days.
2023-05-15 buy  at 1716.30 rmb.
2023-05-16 sell at 1703.29 rmb, yield -0.76% in 1 days.
2023-05-19 buy  at 1699.50 rmb.
2023-05-24 sell at 1710.90 rmb, yield 0.67% in 5 days.
2023-06-02 buy  at 1670.60 rmb.
2023-06-19 sell at 1744.00 rmb, yield 4.39% in 17 days.
Yield 2.14% in half a year.
代码
文本

可以看到,新的策略似乎是有效的,例如在1月5日选择追涨,2月9号选择抄底买入,半年的时间内收益率有约2%,已经比存在银行里好多了。

然而,因为依赖于二阶信息,导致指标受噪音影响很大,单次持有的时间和先前的策略相比明显变短,交易次数变多。

如果我们进一步平滑指标呢?下面我们用MACD柱长3天的EMA替代MACD本身的柱长进行判断,沿用先前的策略:

代码
文本
[12]
buy_price = buy_date = None
results = []
prev_i = None
smoothed_hg = hg.ewm(span=3, adjust=False).mean()
for t, i, p in zip(df.index, smoothed_hg, df.Close):
if prev_i is None:
pass
elif i - prev_i > 0.0 and buy_price is None: # MACD有上升趋势
buy_price = p
buy_date = t
print(t.strftime('%Y-%m-%d'),
f"buy at {p:.2f} rmb.")
elif i - prev_i < -0.0 and buy_price is not None: # MACD有下降趋势
y = (p - buy_price) / buy_price
print(t.strftime('%Y-%m-%d'),
f"sell at {p:.2f} rmb, yield {100*y:.2f}% in {(t - buy_date).days:d} days.")
print(i, prev_i)
buy_price = buy_date = None
results.append(y)
prev_i = i

print(f"Yield {sum(results)*100:.2f}% in half a year.")

2023-01-05 buy  at 1801.00 rmb.
2023-01-18 sell at 1893.00 rmb, yield 5.11% in 13 days.
14.350153221979244 15.149257932466773
2023-02-09 buy  at 1818.00 rmb.
2023-02-22 sell at 1836.00 rmb, yield 0.99% in 13 days.
-0.5168171213447168 -0.4348288029108659
2023-03-01 buy  at 1838.53 rmb.
2023-03-06 sell at 1807.14 rmb, yield -1.71% in 5 days.
-3.835995167752503 -3.7214150171423794
2023-03-14 buy  at 1766.00 rmb.
2023-04-06 sell at 1796.96 rmb, yield 1.75% in 23 days.
6.7778851939499605 7.184590592881655
2023-04-17 buy  at 1753.00 rmb.
2023-04-24 sell at 1705.00 rmb, yield -2.74% in 7 days.
-2.9195562906693677 -2.1572888601434954
2023-04-25 buy  at 1730.38 rmb.
2023-05-08 sell at 1720.52 rmb, yield -0.57% in 13 days.
1.9301777930149975 2.597445557473686
2023-05-19 buy  at 1699.50 rmb.
2023-05-25 sell at 1701.00 rmb, yield 0.09% in 6 days.
1.1246041871294998 1.2663652251434931
2023-06-02 buy  at 1670.60 rmb.
2023-06-20 sell at 1743.46 rmb, yield 4.36% in 18 days.
12.668977671606266 12.928980241384446
Yield 7.29% in half a year.
代码
文本

可以看到,买点和卖点的选择基本上是准确的,收益率也提升到了7%左右!考虑到周期起止端点股票收益率基本为0,这样的收益表现很令人满意了。

当然,这一指标仅仅在单股上做了验证,并没有什么实证意义——有兴趣的读者可以在Notebook前面的代码块中将target从茅台(600519)改为五粮液(000858)试试,结果可能会让你大跌眼镜。

最后还是那句话:股市有风险,投资需谨慎!

代码
文本
量化交易
量化交易
已赞11
本文被以下合集收录
测试合集文章列表100篇
xingyanshi@dp.tech很长的名字xingyanshi@dp.tech很长的名字很长的
更新于 2024-08-04
104 篇2 人关注
量化交易
sai_xu
更新于 2024-06-29
3 篇1 人关注
推荐阅读
公开
《量化投资》(二)量化投资策略:案例代码实现
量化交易
量化交易
chenwj
发布于 2023-09-27
1 转存文件
公开
Molecular mechanics (MM) fitting on subsampled PhAlkEthOH dataset.
机器学习及其在化学中的应用
机器学习及其在化学中的应用
_Maple_F710
发布于 2024-01-14