基於python的量化交易分析
採用:
1. N日擇時策略+ATR風險控制
# N日擇時策略+ATR
def Nbreakstrategy(self,data, N1, N2, n_win, n_loss):
# N1天內最高價
global start
data['N1_high'] = data.High.rolling(window=N1).max()
data['N1_high'] = data.N1_high.shift(1)
max_val = data.Close.expanding().max()
data['N1_high'].fillna(value=max_val, inplace=True)
# N2天內最低價
data['N2_low'] = data.Low.rolling(window=N2).min()
data['N2_low'] = data.N2_low.shift(1)
min_val = data.Close.expanding().min()
data['N2_low'].fillna(value=min_val, inplace=True)
# ATR止盈止損判斷
buy_price = 0
for k_index, today in data.iterrows():
tick = round(today.Close * 0.01, 2)
# 買入
if (today.Close - tick) > today.N1_high:
print('N day buy: {} {}'.format(k_index,today.Close))
buy_price = today.Close
data.loc[k_index, 'signal'] = 1
# 止損,收盤價少於買入價,賣出
elif (buy_price != 0) and (buy_price > today.Close + tick) and ((buy_price - today.Close - tick) > n_loss * today.atr14):
#print('stop loss: {} {} {}'.format(k_index, today.Close, buy_price))
data.loc[k_index, 'signal'] = 0
buy_price = 0
# 止盈:收盤價多於買入價,賣出
elif (buy_price != 0) and (buy_price < today.Close - tick) and ((today.Close - buy_price + tick) > n_win * today.atr14):
#print('stop win: {} {} {}'.format(k_index, today.Close, buy_price))
data.loc[k_index, 'signal'] = 0
buy_price = 0
elif today.Close + tick < today.N2_low:
#print('N day sell: {} {}'.format(k_index, today.Close))
data.loc[k_index, 'signal'] = 0
buy_price = 0
else:
pass
# 買入 / 賣出信號list
data['signal'].fillna(method='ffill', inplace = True)
data['signal'] = data.signal.shift(1)
data['signal'].fillna(method='bfill', inplace=True)
for k_index, today in data.iterrows():
# 買入/賣出 執行
if today.signal == 1 and self.hold_state == 0: # 買入
start = data.index.get_loc(k_index) # 區間開始日期
self.hold_state = -1
self.stock_num = int(self.init_money / today.Close) # 資金轉化爲股票
# 倉位管理
self.send_order(code=self.stock_code, amount=int(self.init_money * 0.01 / today.atr14),
price=today.Close, order_type='buy')
self.init_money = 0
self.graph_trade.annotate('買入',xy=(k_index,data.Close.asof(k_index)),
xytext=(k_index,data.Close.asof(k_index)+2),
arrowprops=dict(facecolor='r',shrink=0.1),
horizontalalignment='left',verticalalignment='top')
elif today.signal == 0 and self.hold_state == -1: # 賣出
end = data.index.get_loc(k_index)
# 手續費:印花稅1‰,手續費5元
profit = self.stock_num * today.Close
fee = profit * 0.0001 - 5
self.init_money = round((profit - fee),1) # 股票轉化爲資金
self.hold_state = 0
self.market_value = 0
# 倉位管理
self.send_order(code=self.stock_code, amount=self.hold_available(code = "600410.SS"), price=today.Close, order_type='sell')
if data.Close[end] < data.Close[start]:
# 賠錢,綠色
self.graph_trade.fill_between(data.index[start:end],0,
data.Close[start:end],color='green',alpha=0.8)
else:
# 賺錢 紅色
self.graph_trade.fill_between(data.index[start:end], 0,
data.Close[start:end], color='red', alpha=0.8)
self.graph_trade.annotate('賣出',xy=(k_index,data.Close.asof(k_index)),
xytext=(k_index+datetime.timedelta(days=5),
data.Close.asof(k_index)+2),
arrowprops=dict(facecolor='g',shrink=0.1),
horizontalalignment='left',verticalalignment='top')
latest_val = self.latest_assets(today.Close)
data.loc[k_index, 'total_position'] = latest_val
if self.hold_state == -1: # 持股狀態
self.market_value = int(self.stock_num * today.Close)
data.loc[k_index, 'total'] = self.market_value
else: # 空倉
data.loc[k_index, 'total'] = self.init_money
print('total value is {}'.format(data['total'][-1]))
self.resultanalysis(data)
return data['total'][-1] # 每次返回
複製代碼
2. 蒙特卡洛優化算法優化策略輸入參數
# 使用蒙特卡洛方法挑選出最優的N1,N2,止盈,止損點
# 25,5,2.3,0.7
def montcarlo(self,data, n):
n1_min, n1_max = 10, 30
n2_min, n2_max = 5, 15
win_min, win_max = 1.5, 3
loss_min, loss_max = 0.5, 1.2
ma_ls = []
profit_ls = []
# 每次隨機生成一組N1,N2,止盈,止損倍數,循環N日擇時策略並把每次執行策略的最終資產存入數組
# 最終獲得n次執行後,獲得最大資產的一組隨機數,做爲最優策略的輸入參數
for i in range(0, n+1):
n1 = int(random.uniform(n1_min,n1_max))
n2 = int(random.uniform(n2_min, n2_max))
win = round(random.uniform(win_min, win_max),1)
loss = round(random.uniform(loss_min, loss_max),1)
ma_ls.append([n1,n2,win,loss])
# 策略代碼
trade = QuantAnalysis()
profit_ls.append(trade.Nbreakstrategy(data, n1, n2, win, loss))
profit_max = max(profit_ls)
ma_max = ma_ls[profit_ls.index(profit_max)]
print("maximize the profit is %s and correspond parametes are %s " % (profit_max, ma_max))
return ma_ls
複製代碼
3. 基於ATR的倉位管理
# 倉位管理
self.send_order(code=self.stock_code, amount=int(self.init_money * 0.01 / today.atr14),price=today.Close, order_type='buy')
self.send_order(code=self.stock_code, amount=self.hold_available(code = "600410.SS"), price=today.Close, order_type='sell')
複製代碼
4. 滑點收盤價的1%
在每一次買入賣出,止盈止損的過程當中加入滑點值,讓結果沒那麼‘完美’,更符合實際的狀況。
複製代碼
5. 印花稅 1‰,手續費5元
在賣出時將印花稅,手續費加入
profit = self.stock_num * today.Close
fee = profit * 0.0001 - 5
複製代碼
6. 結果生成圖像:
a. 買賣區間圖
b. 基準收益/策略收益對比圖
c. 總資產圖(無策略的總資產+N日擇時策略下的總資產+倉位管理的總資產+最大總資產)
無倉位管理,無手續費,通過蒙特卡洛篩選出最優N日擇時策略後的執行結果圖
複製代碼
增長倉位管理,增長手續費後的結果圖,能夠對比看出倉位管理的優點,總資產比不實施倉位管理要高了不少
複製代碼
從圖中能夠看出當買入點較高時,股票開始下跌,策略可以及時止損,本次策略使用的止損點爲0.7,賣出時可以較好的獲利,止盈點爲2.3。
採用量化分析的方式,能夠對一隻股票的交易歷史有一個很好的分析,經過模擬策略來進行買賣,檢驗本身策略的好壞,可是有個疑問,怎麼樣可以經過策略來決定當下要是否要買這支股票呢?複製代碼