# 技术分析入门 —— 双均线策略

## 1. 准备工作

• `matplotlib` 用于绘制图表
• `numpy` 时间序列的计算
• `pandas` 处理结构化的表格数据
• `DataAPI` 通联数据提供的数据API
• `seaborn` 用于美化matplotlib图表
``````from matplotlib import pylab
import numpy as np
import pandas as pd
import DataAPI
import seaborn as sns
sns.set_style('white')
``````

• 起始：2008年1月1日
• 结束：2015年4月23日

``````secID = '510050.XSHG'
start = '20080101'
end = '20150423'

security = DataAPI.MktFunddGet(secID, beginDate=start, endDate=end, field=['tradeDate', 'closePrice'])
security.info()

<class 'pandas.core.frame.DataFrame'>
DatetimeIndex: 1775 entries, 2008-01-02 00:00:00 to 2015-04-23 00:00:00
Data columns (total 1 columns):
closePrice    1775 non-null float64
dtypes: float64(1)
``````

``````security.tail()
``````
closePrice
2015-04-17 3.185
2015-04-20 3.103
2015-04-21 3.141
2015-04-22 3.241
2015-04-23 3.212

``````security['closePrice'].plot(grid=False, figsize=(12,8))
sns.despine()
``````

## 2. 策略描述

• 短期均线： `window_short = 20`，相当于月均线
• 长期均线： `window_long = 120`，相当于半年线
• 偏离度阈值： `SD = 5%`，区间宽度，这个会在后面有详细解释

``````window_short = 20
window_long = 120
SD = 0.05

security['short_window'] = np.round(pd.rolling_mean(security['closePrice'], window=window_short), 2)
security['long_window'] = np.round(pd.rolling_mean(security['closePrice'], window=window_long), 2)
security[['closePrice', 'short_window', 'long_window']].tail()
``````
closePrice short_window long_window
2015-04-17 3.185 2.82 2.30
2015-04-20 3.103 2.85 2.31
2015-04-21 3.141 2.87 2.33
2015-04-22 3.241 2.90 2.34
2015-04-23 3.212 2.93 2.35

``````security[['closePrice', 'short_window', 'long_window']].plot(grid=False, figsize=(12,8))
sns.despine()
``````

### 2.1 定义信号

``````security['s-l'] = security['short_window'] - security['long_window']
security['s-l'].tail()

2015-04-17    0.52
2015-04-20    0.54
2015-04-21    0.54
2015-04-22    0.56
2015-04-23    0.58
Name: s-l, dtype: float64
``````

• `s−l>SD×long_window`，支持买入，定义`Regime``True`
• 其他情形下，卖出信号，定义`Regime``False`
``````security['Regime'] = np.where(security['s-l'] > security['long_window'] * SD, 1, 0)
security['Regime'].value_counts()

0    1394
1     381
dtype: int64
``````

``````security['Regime'].plot(grid=False, lw=1.5, figsize=(12,8))
pylab.ylim((-0.1,1.1))
sns.despine()
``````

``````security['Market'] = np.log(security['closePrice'] / security['closePrice'].shift(1))
security['Strategy'] = security['Regime'].shift(1) * security['Market']
security[['Market', 'Strategy', 'Regime']].tail()
``````
Market Strategy Regime
2015-04-17 0.012638 0.012638 1
2015-04-20 -0.026083 -0.026083 1
2015-04-21 0.012172 0.012172 1
2015-04-22 0.031341 0.031341 1
2015-04-23 -0.008988 -0.008988 1

``````security[['Market', 'Strategy']].cumsum().apply(np.exp).plot(grid=False, figsize=(12,8))
sns.despine()
``````

## 3 使用`quartz`实现策略

``````start = datetime(2008, 1, 1)                # 回测起始时间
end  = datetime(2015, 4, 23)                # 回测结束时间
benchmark = 'SH50'                            # 策略参考标准
universe = ['510050.XSHG']    # 股票池
capital_base = 100000     # 起始资金
commission = Commission(0.0,0.0)

window_short = 20
window_long = 120
longest_history = window_long
SD = 0.05

def initialize(account):                    # 初始化虚拟账户状态
account.fund = universe[0]
account.SD = SD
account.window_short = window_short
account.window_long = window_long

def handle_data(account):             # 每个交易日的买入卖出指令
hist = account.get_history(longest_history)
fund = account.fund
short_mean = np.mean(hist[fund]['closePrice'][-account.window_short:]) # 计算短均线值
long_mean = np.mean(hist[fund]['closePrice'][-account.window_long:])   #计算长均线值

# 计算买入卖出信号
flag = True if (short_mean - long_mean) > account.SD * long_mean else False
if flag:
if account.position.secpos.get(fund, 0) == 0:
# 空仓时全仓买入，买入股数为100的整数倍
approximationAmount = int(account.cash / hist[fund]['closePrice'][-1]/100.0) * 100
order(fund, approximationAmount)
else:
# 卖出时，全仓清空
if account.position.secpos.get(fund, 0) >= 0:
order_to(fund, 0)
``````