Scikit-Learn 股票投资:p20

前言

正如上一教程提及到的,股票投资不是说胜率高就一定赚钱,胜率低就一定亏。我们有可能80%的胜率,每次赚¥1;但有20%的失败率,每次输¥100。所以为了解决这个问题,我们除了要考虑其准确率外,还要考虑到股票的回报率。 本次视频教学将会添加一系列的投资回报率作为参考。

视频

视频出处

视频系列:Scikit-learn Machine Learning with Python and SKlearn

本视频出处:Scikit Learn Machine Learning for investing Tutorial with Python p. 20

哔哩哔哩:Scikit Learn Machine Learning for investing Tutorial with Python p. 20

内容

首先,我们在def Build_Data_Set中添加新的变量Z,用作。

Z = np.array(data_df[['stock_p_change','sp500_p_change']])

return X, y, Z

接下来在Analysis()下添加如下代码用作初始化投资金额、回报率等:

    #投资金额
    invest_amount = 10000
    #交易次数
    total_invests = 0
    #用于累计sp500的回报率
    if_market = 0
    #用于累计策略的回报率
    if_strat = 0

然后在for 下添加:

        #如果股票优于大盘,分别计算其回报率
        if clf.predict(X[-x])[0] == 1:
            invest_return = invest_amount + (invest_amount*(Z[-x][0]/100))
            market_return = invest_amount + (invest_amount*(Z[-x][1]/100))
            #用于累计交易次数、投资回报率
            total_invests +=1
            if_market += market_return
            if_strat += invest_return            

最后就是添加平均收益的计算:

    compared = (if_strat - if_market)/if_market * 100
    do_nothing = total_invests * invest_amount
    
    avg_market = (if_market - do_nothing)/ do_nothing * 100
    avg_strat  = (if_strat - do_nothing)/ do_nothing * 100
    
    print('accuracy:', (correct_count/test_size)*100)
    print('Total Trades:',total_invests)
    print('Ending with strategy:',if_strat)
    print('Ending with market:',if_market)
    print('compared to market, we earn ', str(compared)+'% more')
    print('Average investment return: ', str(avg_strat)+'%')
    print('Average market return: ' ,str(avg_market)+'%')

最后的结果和作者在视频得出的有很大出入,但思路是一样的:

2960
accuracy: 59.3
Total Trades: 757
Ending with strategy: -7888259.0
Ending with market: 8550520.0
compared to market, we earn  -192.254728367% more
Average investment return:  -204.204214003%
Average market return:  12.9527080581%

源代码

import numpy as np
from sklearn import svm ,preprocessing
import pandas as pd
import matplotlib
import matplotlib.pyplot as plt
from matplotlib import style
style.use("ggplot")
import statistics 

FEATURES =  [
  'DE Ratio',
  'Trailing P/E',
  'Price/Sales',
  'Price/Book',
  'Profit Margin',
  'Operating Margin',
  'Return on Assets',
  'Return on Equity',
  'Revenue Per Share',
  'Market Cap',
  'Enterprise Value',
  'Forward P/E',
  'PEG Ratio',
  'Enterprise Value/Revenue',
  'Enterprise Value/EBITDA',
  'Revenue',
  'Gross Profit',
  'EBITDA',
  'Net Income Avl to Common ',
  'Diluted EPS',
  'Earnings Growth',
  'Revenue Growth',
  'Total Cash',
  'Total Cash Per Share',
  'Total Debt',
  'Current Ratio',
  'Book Value Per Share',
  'Cash Flow',
  'Beta',
  'Held by Insiders',
  'Held by Institutions',
  'Shares Short (as of',
  'Short Ratio',
  'Short % of Float',
  'Shares Short (prior '
]

def Build_Data_Set(features = FEATURES):
    #读取key_stats.csv
    data_df = pd.DataFrame.from_csv("key_stats_acc_perf_WITH_NA.csv")
    
    data_df = data_df.reindex(np.random.permutation(data_df.index))
    #替代N/A数据
    data_df = data_df.replace('NaN',-9999).replace('N/A',-9999)
    
    #将features转换为np.array
    X = np.array(data_df[features].values)
    
    #将'outperform和outperform'和转换为0 和 1, 因为machine learning只会区分数字
    y = (data_df['Status']
         .replace('underperform', 0)
         .replace('outperform',1)
         .values.tolist())
    
    X = preprocessing.scale(X)
    
    Z = np.array(data_df[['stock_p_change','sp500_p_change']])


    return X, y, Z


def Analysis():
    #用于回测侧数据大小
    test_size = 1000    
    
    invest_amount = 10000
    total_invests = 0
    if_market = 0
    if_strat = 0
    
    X, y,Z = Build_Data_Set()
    print(len(X))
    
    #设为linear回归模型
    clf = svm.SVC(kernel = 'linear', C=1.0)
    #训练我们的模型
    clf.fit(X[:-test_size],y[:-test_size])
    
    correct_count = 0
    
    for x in range(1, test_size+1):
        if clf.predict(X[-x])[0] == y[-x]:
            correct_count += 1
        #优于大盘
        if clf.predict(X[-x])[0] == 1:
            invest_return = invest_amount + (invest_amount*(Z[-x][0]/100))
            market_return = invest_amount + (invest_amount*(Z[-x][1]/100))
            
            total_invests +=1
            if_market += market_return
            if_strat += invest_return
             
    print('accuracy:', (correct_count/test_size)*100)
    print('Total Trades:',total_invests)
    print('Ending with strategy:',if_strat)
    print('Ending with market:',if_market)
    
    compared = (if_strat - if_market)/if_market * 100
    do_nothing = total_invests * invest_amount
    
    avg_market = (if_market - do_nothing)/ do_nothing * 100
    avg_strat  = (if_strat - do_nothing)/ do_nothing * 100
    
    print('compared to market, we earn ', str(compared)+'% more')
    print('Average investment return: ', str(avg_strat)+'%')
    print('Average market return: ' ,str(avg_market)+'%')

Analysis()

结论

我们从yahoo下载的数据有缺失的问题。实际上我们本应该有500个股票数据用作测试,但实际上yahoo上下载的数据存在缺失,我们实际用到的数据只有300多家。这对sklearn的准确性有一定影响。作者建议改用Russell3000作为测试数据。

还有一个问题是,我们所用的sp500数据是基于2013年,然后利用其历史数据进行回测。 但问题是sp500指数里的公司不是一直固定不变的,很有可能在2002年的时候有些经营不善的公司早已被收购或者私有化退出sp500了。 那么这里存在一个问题。我们本来希望通过Machine Learning(机器学习)来学习区分优于和劣于大盘的公司,但优胜劣汰的市场机制早已将劣质的公司过滤掉了,那么我们用的数据早已是存在偏差(bias) 。所以最好的解决方法是,每一个季度或者每一年对sp500的股票数据重新跟踪测算,然后看看假设当初这公司没有被过滤掉,自己是否会投资。

最后

虽然分c君_BingWong只是作为一名搬运工,连码农都称不上。 但制作代码中的注释、翻译和搬运都花了很多时间,请各位大侠高抬贵手,在转载时请注明出处。

添加新评论