# Python量化交易-MA/MACD

MACD称为异同移动平均线，是从双指数移动平均线发展而来的。

``````def moving_average(x, n, type='simple'):
"""
compute an n period moving average.

type is 'simple' | 'exponential'

"""
x = np.asarray(x)
if type == 'simple':
weights = np.ones(n)
else:
weights = np.exp(np.linspace(-1., 0., n))
weights /= weights.sum()
a = np.convolve(x, weights, mode='full')[:len(x)]
a[:n] = a[n]
return a``````
``````def moving_average_convergence(x, nslow=26, nfast=12):

emaslow = moving_average(x, nslow, type='exponential')
emafast = moving_average(x, nfast, type='exponential')
return emaslow, emafast, emafast - emaslow``````

``````import matplotlib.dates as mdates
import matplotlib.font_manager as font_manager
import matplotlib.pyplot as plt
import matplotlib.ticker as mticker
import numpy as np
import pandas as pd
import tushare as ts

# ticker = 'SPY'
# r = pd.read_csv('data/yahoofinance-SPY-20080101-20180101.csv',
#                 index_col=0,
#                 parse_dates=True,
#                 infer_datetime_format=True)

def moving_average(x, n, type='simple'):
"""
compute an n period moving average.

type is 'simple' | 'exponential'

"""
x = np.asarray(x)
if type == 'simple':
weights = np.ones(n)
else:
weights = np.exp(np.linspace(-1., 0., n))
weights /= weights.sum()
a = np.convolve(x, weights, mode='full')[:len(x)]
a[:n] = a[n]
return a

def relative_strength(prices, n=14):
"""
compute the n period relative strength indicator
"""
deltas = np.diff(prices)
seed = deltas[:n + 1]
up = seed[seed >= 0].sum() / n
down = -seed[seed < 0].sum() / n
rs = up / down
rsi = np.zeros_like(prices)
rsi[:n] = 100. - 100. / (1. + rs)
for i in range(n, len(prices)):
delta = deltas[i - 1]  # cause the diff is 1 shorter
if delta > 0:
upval = delta
downval = 0.
else:
upval = 0.
downval = -delta
up = (up * (n - 1) + upval) / n
down = (down * (n - 1) + downval) / n
rs = up / down
rsi[i] = 100. - 100. / (1. + rs)

return rsi

def moving_average_convergence(x, nslow=26, nfast=12):
"""
compute the MACD (Moving Average Convergence/Divergence)
using a fast andslow exponential moving avg
return value is emaslow, emafast, macd which are len(x) arrays
"""
emaslow = moving_average(x, nslow, type='exponential')
emafast = moving_average(x, nfast, type='exponential')
return emaslow, emafast, emafast - emaslow
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# 获取数据，下载2018年到现在的每天的交易数据
r = ts.get_k_data('600519', ktype='D', autype='qfq', start='2018-01-01', end='')
r.index = pd.to_datetime(r['date'])
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
#

plt.rc('axes', grid=True)
plt.rc('grid', color='0.75', linestyle='-', linewidth=0.5)
textsize = 9
left, width = 0.1, 0.8
rect1 = [left, 0.7, width, 0.2]
rect2 = [left, 0.3, width, 0.4]
rect3 = [left, 0.1, width, 0.2]

#  szhs设置选择的 绘制区域
fig = plt.figure(facecolor='white',figsize=(19,10))
axescolor = '#f6f6f6'  # the axes background color
ax1 = fig.add_axes(rect1, facecolor=axescolor)  # left, bottom, width, height
ax2 = fig.add_axes(rect2, facecolor=axescolor, sharex=ax1)
ax2t = ax2.twinx()
ax3 = fig.add_axes(rect3, facecolor=axescolor, sharex=ax1)

#  RSI 指标模型
# plot the relative strength indicator
prices = r["close"]
rsi = relative_strength(prices)
fillcolor = 'darkgoldenrod'
ax1.plot(r.index, rsi, color=fillcolor)
# 30 70 两条线，这是阈值线
ax1.axhline(70, color=fillcolor)
ax1.axhline(30, color=fillcolor)
ax1.fill_between(r.index, rsi, 70, where=(rsi >= 70),facecolor=fillcolor, edgecolor=fillcolor)
ax1.fill_between(r.index, rsi, 30, where=(rsi <= 30),facecolor=fillcolor, edgecolor=fillcolor)
ax1.text(0.6, 0.9, '>70 = overbought', va='top',transform=ax1.transAxes, fontsize=textsize)
ax1.text(0.6, 0.1, '<30 = oversold',transform=ax1.transAxes, fontsize=textsize)
# 设置纵轴的范围
ax1.set_ylim(0, 100)
ax1.set_yticks([30, 70])
ax1.text(0.025, 0.95, 'RSI (14)', va='top',transform=ax1.transAxes, fontsize=textsize)
ax1.set_title('贵州茅台（600519）', fontproperties="SimHei")

# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# plot the price and volumedata
dx = r["close"] - r.close
low = r.low + dx
high = r.high + dx
#  绘制蜡烛线
deltas = np.zeros_like(prices)
deltas[1:] = np.diff(prices)
up = deltas > 0
ax2.vlines(r.index[up], low[up], high[up], color='red', label='_nolegend_')
ax2.vlines(r.index[~up], low[~up], high[~up],color='green', label='_nolegend_')
# 绘制均线
# 计算均线
ma5 = moving_average(prices, 5, type='simple')
ma10 = moving_average(prices, 10, type='simple')
ma30 = moving_average(prices, 30, type='simple')
ma60 = moving_average(prices, 60, type='simple')
ma120 = moving_average(prices, 120, type='simple')
linema5, = ax2.plot(r.index, ma5, color='yellow', lw=1, label='MA (5)')
linema10, = ax2.plot(r.index, ma10, color='magenta', lw=1, label='MA (10)')
linema30, = ax2.plot(r.index, ma30, color='lime', lw=1, label='MA (30)')
linema60, = ax2.plot(r.index, ma60, color='gold', lw=1, label='MA (60)')
linema120, = ax2.plot(r.index, ma120, color='blue', lw=1, label='MA (120)')

# # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # #
#  交易量
last = r.tail(1)
s = '%s O:%1.2f H:%1.2f L:%1.2f C:%1.2f, V:%1.1fM Chg:%+1.2f' % (
last.index.strftime('%Y.%m.%d')[0],
last.open, last.high,
last.low, last.close,
last.volume* 1e-6,
last.close - last.open)
t4 = ax2.text(0.3, 0.9, s, transform=ax2.transAxes, fontsize=textsize)

props = font_manager.FontProperties(size=10)
leg = ax2.legend(loc='center left', shadow=True, fancybox=True, prop=props)
leg.get_frame().set_alpha(0.5)

volume= (r.close * r.volume) / 1e6  # dollar volumein millions
vmax = volume.max()
poly = ax2t.fill_between(r.index, volume, 0, label='volume',
facecolor=fillcolor, edgecolor=fillcolor)
ax2t.set_ylim(0, 5 * vmax)
ax2t.set_yticks([])

# # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # # # # # # # # #
# # # # # # # # # # # #
# compute the MACD indicator
fillcolor = 'darkslategrey'
nslow = 26
nfast = 12
nema = 9
emaslow, emafast, macd = moving_average_convergence(prices,
nslow=nslow, nfast=nfast)

ema9 = moving_average(macd, nema, type='exponential')
ax3.plot(r.index, macd, color='black', lw=2)
ax3.plot(r.index, ema9, color='blue', lw=1)
ax3.fill_between(r.index, macd - ema9, 0, alpha=0.5,
facecolor=fillcolor, edgecolor=fillcolor)
ax3.text(0.025, 0.95, 'MACD (%d, %d, %d)' % (nfast, nslow, nema), va='top',
transform=ax3.transAxes, fontsize=textsize)

# ax3.set_yticks([])
# turn off upper axis tick labels, rotate the lower ones, etc
# for ax in ax1, ax2, ax2t, ax3:
#     if ax != ax3:
#         for label in ax.get_xticklabels():
#             label.set_visible(False)
#     else:
#         for label in ax.get_xticklabels():
#             label.set_rotation(30)
#             label.set_horizontalalignment('right')
#
#     ax.fmt_xdata = mdates.DateFormatter('%Y-%m-%d')

class MyLocator(mticker.MaxNLocator):
def __init__(self, *args, **kwargs):
mticker.MaxNLocator.__init__(self, *args, **kwargs)

def __call__(self, *args, **kwargs):
return mticker.MaxNLocator.__call__(self, *args, **kwargs)

# at most 5 ticks, pruning the upper and lower so they don't overlap
# with other ticks
# ax2.yaxis.set_major_locator(mticker.MaxNLocator(5, prune='both'))
# ax3.yaxis.set_major_locator(mticker.MaxNLocator(5, prune='both'))

ax2.yaxis.set_major_locator(MyLocator(5, prune='both'))
ax3.yaxis.set_major_locator(MyLocator(1, prune='both'))

plt.show()``````