股票组合 | 用Python玩玩股票投资组合进行量化交易

前两篇公号文章主要讲了如何获取股票数据,进行股票走势可视化,进而我们可以根据一定投资策略选择长线和短线的移动平均计算金叉和死叉信号确定买卖信号,测算投资收益。

我们再次要假设你的投资策略:

1-你投入股票一笔资金,这里假设100万人民币;

2-你有选对的多只股票用于相对长线的投资策略——股票篮子;

3-你设定的相对长线的预期盈利目标,收益=10%;

4-你有设定的相对长线的止损底线,止损=20%——亏损20%就抛掉股票;

俺不炒股也不太懂股票,这里目的还是告诉大家用Python如何玩玩,建模啥的。所以我找人告诉我假设的10只股票,作为我们测试的股票篮子。

600050中国联通,600519贵州茅台,002186全聚德,600085同仁堂,000002万科A,601398工商银行,000917电广传媒,600030中信证券,000027深圳能源,000665湖北广电

这篇主要讲如果这10只投资组合算法:

我们应该知道,我们不该把所有的鸡蛋放在一个篮子里,也不会傻到只是在最晚时间点交易,而应该选择最低股票价格点交易,所以在移动平均线下的最低交易日更理想。

如何获取股票数据和相关单只股票Buy-Sell时间点可以看前面的文章。

我们依然先用贵州茅台GZMT来说明:

我们首先修正股票价格,用adj close价格修正Open、High、Low、Close价格

采用的算法是:

我们后面就用修正股票数据进行分析:

修正后的股票Buy-Sell时间的交易利润有了一定变化,选择更低股价交易日买。


好了,现在假设我们买卖股票为100手

在假设100万人民币投资基础上,计算gzmt的投资收益情况:

如果100万只投资贵州茅台,在一年的时间内长线投资收益还是不错的。

现在我们进行多只股票的投资组合的收益回溯分析(以前面的10支A股为例,作为投资股票池)

我们需要根据前面的算法构建一个定义函数:


def ma_crossover_orders(stocks, fast, slow):

fast_str = str(fast) + ‘d’

slow_str = str(slow) + ‘d’

ma_diff_str = fast_str + ‘-‘ + slow_str

trades = pd.DataFrame({“Price”: [], “Regime”: [], “Signal”: []})

for s in stocks:

s[1][fast_str] = np.round(s[1][“Close”].rolling(window = fast, center = False).mean(), 2)

s[1][slow_str] = np.round(s[1][“Close”].rolling(window = slow, center = False).mean(), 2)

s[1][ma_diff_str] = s[1][fast_str] – s[1][slow_str]

s[1][“Regime”] = np.where(s[1][ma_diff_str] > 0, 1, 0)

s[1][“Regime”] = np.where(s[1][ma_diff_str] < 0, -1, s[1][“Regime”])

regime_orig = s[1].ix[-1, “Regime”]

s[1].ix[-1, “Regime”] = 0

s[1][“Signal”] = np.sign(s[1][“Regime”] – s[1][“Regime”].shift(1))

s[1].ix[-1, “Regime”] = regime_orig

signals = pd.concat([

pd.DataFrame({“Price”: s[1].loc[s[1][“Signal”] == 1, “Close”],

“Regime”: s[1].loc[s[1][“Signal”] == 1, “Regime”],

“Signal”: “Buy”}),

pd.DataFrame({“Price”: s[1].loc[s[1][“Signal”] == -1, “Close”],

“Regime”: s[1].loc[s[1][“Signal”] == -1, “Regime”],

“Signal”: “Sell”}),

])

signals.index = pd.MultiIndex.from_product([signals.index, [s[0]]], names = [“Date”, “Symbol”])

trades = trades.append(signals)

trades.sort_index(inplace = True)

trades.index = pd.MultiIndex.from_tuples(trades.index, names = [“Date”, “Symbol”])

return trades

def backtest(signals, cash, port_value = .1, batch = 100):

SYMBOL = 1

portfolio = dict()

port_prices = dict()

results = pd.DataFrame({“Start Cash”: [],

“End Cash”: [],

“Portfolio Value”: [],

“Type”: [],

“Shares”: [],

“Share Price”: [],

“Trade Value”: [],

“Profit per Share”: [],

“Total Profit”: []})

for index, row in signals.iterrows():

shares = portfolio.setdefault(index[SYMBOL], 0)

trade_val = 0

batches = 0

cash_change = row[“Price”] * shares

portfolio[index[SYMBOL]] = 0

old_price = port_prices.setdefault(index[SYMBOL], row[“Price”])

portfolio_val = 0

for key, val in portfolio.items():

portfolio_val += val * port_prices[key]

if row[“Signal”] == “Buy” and row[“Regime”] == 1:

batches = np.floor((portfolio_val + cash) * port_value) // np.ceil(batch * row[“Price”])

trade_val = batches * batch * row[“Price”]

cash_change -= trade_val

portfolio[index[SYMBOL]] = batches * batch

port_prices[index[SYMBOL]] = row[“Price”]

old_price = row[“Price”]

elif row[“Signal”] == “Sell” and row[“Regime”] == -1:

pass

# Do nothing; can we provide a method for shorting the market?

#else:

#raise ValueError(“I don’t know what to do with signal ” + row[“Signal”])

pprofit = row[“Price”] – old_price

results = results.append(pd.DataFrame({

“Start Cash”: cash,

“End Cash”: cash + cash_change,

“Portfolio Value”: cash + cash_change + portfolio_val + trade_val,

“Type”: row[“Signal”],

“Shares”: batch * batches,

“Share Price”: row[“Price”],

“Trade Value”: abs(cash_change),

“Profit per Share”: pprofit,

“Total Profit”: batches * batch * pprofit

}, index = [index]))

cash += cash_change

results.sort_index(inplace = True)

results.index = pd.MultiIndex.from_tuples(results.index, names = [“Date”, “Symbol”])

return results


函数需要三个参数:股票名称、短线周期=20d、长线周期=50d


我也不知道10支股票中文名称,俺就用字母拼音了。

现在抓取了2016-1-1至今10支A股股票的收盘数据,经过Adj-Close的修正,在20d和50d移动平均的交叉点策略下,以100万人民币投资,每手交易100股的假定条件:


交易Buy-Sell结果如下:

最后给出交易收益分析:

bk = backtest(signals, 1000000)

bk

部分结果输出:


从图中我们可以看到,最终的收益并不恨理想,但至少是盈利了,不到4万,哈哈!算法还没用考虑交易的手续费和其他。

最终的投资组合收益曲线是:

看来机器算法或量化投资还是比较保守的,但至少还是没赔钱,当然算法也没用明确止损点的触发。

我们最好来比较一下,如果假设上证指数shanghai可以作为对标的Banchmarking,如果可以假设买上证指数股票的话:


可以看出这样的投资策略:如果单纯购买估计得赔了6万块钱;

但是按照我们的投资模型算法:


基本上还是战胜了指数,尽管没用太多收益,股市嘛,不赔已经不错啦!哈哈

好了,俺费劲写了三篇关于用Python玩股票的文章,其实俺不懂股票,现在少有鞋感觉,如果俺炒股应该是计算派。

但是通过模仿这些算法,俺明白一个重要的应用:今后任何时间序列的预测问题可以采用移动平均的两条线来判断销售或数量指标的拐点和趋势分析。

如果大家没看懂可以参考老外的原创博客:https://ntguardian.wordpress.com/2016/09/26/introduction-stock-market-data-python-2/

来源:沈浩老师(微信公众号:artofdata)

注:数据分析网遵循行业规范,任何转载的稿件都会明确标注作者和来源,若标注有误或遗漏,请联系主编邮箱:afenxi@afenxi.com

编辑

数据分析网编辑Guest,文章均来自网络转载文章,我们会把大数据相关的优秀文章转载推荐给大家,如果您认为本文侵犯了您的版权信息或作者、出处备注有误,请与我们联系修正。联系邮箱afenxi@afenxi.com

分享到:更多

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址