python计算aic_AI教程工具箱系列| 如何使用Python计算MACD的精度

作者:Cameron Shadmehry

编译:Florence Wong – AICUG

本文系AICUG翻译原创,如需转载请联系(微信号:834436689)以获得授权

从统计上来说,如果您盲目地使用相同的技术指标来处理不同的股票,那么通过抛硬币,你或许有更好的运气。

图说:颜色表示MACD预测价格走势的准确性,而大小表示记录的交叉量。

MACD技术指标的准确性非常不稳定,取决于所观察到的库存,它经常跌至50%以下。对于积极利用MACD指标的股票交易者,必须了解每种股票对MACD的敏感性。该代码将使投资者能够确定哪些股票对MACD最敏感,以及哪种股票是最有利的交易策略。

在下面的代码中,我已自动计算了上千股的MACD。通过利用每只股票的完整历史数据,我们可以衡量MACD指标与每个公司相关的预测能力。然后,通过将所有股票按照其特定MACD准确性进行排名,我们可以挑选出最佳股票和实施策略。

必要的库

现在有许多库,面向数据整理和分析1000多种股票。在本节中,我将更多地讨论我们正在使用的每个库的重要性。

# Necessary Libraries

import yfinance as yf, pandas as pd, shutil, os, time, glob

import numpy as np

import requests

from get_all_tickers import get_tickers as gt

from statistics import mean

库:

Yfinance:收集每只股票的历史数据。https://pypi.org/project/yfinance/​pypi.org

Pandas:处理大型数据集。

API reference - pandas 1.0.5 documentation​pandas.pydata.org

Shutil,Glob和 OS:访问计算机上的文件夹/文件。shutil - High-level file operations - Python 3.8.4 documentation​docs.python.org

glob - Unix style pathname pattern expansion - Python 3.8.4 documentation​docs.python.orghttps://docs.python.org/3/library/os.html​docs.python.org

Time:强制程序暂停一段时间。

time - Time access and conversions - Python 3.8.4 documentation​docs.python.org

Get_All_Tickers:筛选所有股票以获得所需的列表。

https://github.com/shilewenuw/get_all_tickers​github.com

numpy:使用数组。

https://numpy.org/​numpy.org

Requests:避免连接错误。

Requests: HTTP for Humans™​requests.readthedocs.io

Statistics:计算指数加权平均值。

statistics - Mathematical statistics functions - Python 3.8.4 documentation​docs.python.org

导入历史库存数据

为了计算MACD在预测每只股票价格走势时的准确性,我们必须首先获取公司上所有可用的历史数据。为此,我们将从缩小要观察的股票列表的范围开始,然后独立链接Yahoo Finance以收集其历史价格数据。

使用Get_All_Tickers库,我们可以获得满足筛选条件的股票列表。就我的例子而言,我只看市值超过50亿美元的股票。这样做为我提供了大约1,026种不同股票的最终清单。

一旦有了一份我们满意的股票清单,下一个循环将循环遍历每个股票,并从Yahoo Finance收集其历史数据。接收到数据后,该程序会将每个公司的信息保存在一个新的CSV文件中,该文件位于名为“股票”的文件夹中。

# If you have a list of your own you would like to use just create a new list instead of using this, for example: tickers = ["FB", "AMZN", ...]

tickers = gt.get_tickers_filtered(mktcap_min=5000, mktcap_max=10000000)

# Check that the amount of tickers isn't more than 2000

print("The amount of stocks chosen to observe: " + str(len(tickers)))

# These two lines remove the Stocks folder and then recreate it in order to remove old stocks. Make sure you have created a Stocks Folder the first time you run this.

shutil.rmtree("\\SMA_Analysis\\Stocks\\")

os.mkdir("\\SMA_Analysis\\Stocks\\")

# Holds the amount of API calls we executed

Amount_of_API_Calls = 0

# This while loop is reponsible for storing the historical data for each ticker in our list. Note that yahoo finance sometimes incurs json.decode errors and because of this we are sleeping for 2

# seconds after each iteration, also if a call fails we are going to try to execute it again.

# Also, do not make more than 2,000 calls per hour or 48,000 calls per day or Yahoo Finance may block your IP. The clause "(Amount_of_API_Calls < 1800)" below will stop the loop from making

# too many calls to the yfinance API.

# Prepare for this loop to take some time. It is pausing for 2 seconds after importing each stock.

# Used to make sure we don't waste too many API calls on one Stock ticker that could be having issues

Stock_Failure = 0

Stocks_Not_Imported = 0

# Used to iterate through our list of tickers

i=0

while (i < len(tickers)) and (Amount_of_API_Calls < 1800):

try:

print("Iteration = " + str(i))

stock = tickers[i] # Gets the current stock ticker

temp = yf.Ticker(str(stock))

Hist_data = temp.history(period="max") # Tells yfinance what kind of data we want about this stock (In this example, all of the historical data)

Hist_data.to_csv("\\SMA_Analysis\\Stocks\\"+stock+".csv") # Saves the historical data in csv format for further processing later

time.sleep(2) # Pauses the loop for two seconds so we don't cause issues with Yahoo Finance's backend operations

Amount_of_API_Calls += 1

Stock_Failure = 0

i += 1 # Iteration to the next ticker

except ValueError:

print("Yahoo Finance Backend Error, Attempting to Fix") # An error occured on Yahoo Finance's backend. We will attempt to retreive the data again

if Stock_Failure > 5: # Move on to the next ticker if the current ticker fails more than 5 times

i+=1

Stocks_Not_Imported += 1

Amount_of_API_Calls += 1

Stock_Failure += 1

# Handle SSL error

except requests.exceptions.SSLError as e:

print("Yahoo Finance Backend Error, Attempting to Fix SSL") # An error occured on Yahoo Finance's backend. We will attempt to retreive the data again

if Stock_Failure > 5: # Move on to the next ticker if the current ticker fails more than 5 times

i+=1

Stocks_Not_Imported += 1

Amount_of_API_Calls += 1

Stock_Failure += 1

print("The amount of stocks we successfully imported: " + str(i - Stocks_Not_Imported))

确定每种股票的MACD精度

在本部分代码中,我们将评估MACD的准确性,以预测每只股票的未来价格走势。为此,我们必须首先创建MACD和信号线(Signal Lines),然后观察它们穿过的时刻。我们将计算预测的价格变动正确的次数,以及不正确的次数。然后,通过比较这些结果,我们可以确定MACD技术指标的真实历史准确性。

一旦我们证实了每种股票的常量,就将它们添加到数据框“ Compare_Stocks”的新行中。然后,在我们遍历每只股票之后,以上数据框将另存为CSV文件,以供进一步分析。至此,我们现在有了一个文件,其中包含每个股票的MACD分析结果。同样在文件中,我们还有其他常量,例如“ Sensitivity”和“ Specificity”,可用于进一步的分析,例如创建ROC曲线。

本部分的一个重要方面,是其易于操作。如果您要判断MACD预测中长期投资的能力,则非常简单,更改12天和26天移动平均。如果您想调整用来判断MACD表现的时间范围,那么您所要做的就是,利用名为“ Avg_Closing_Next_Days”的变量。

# Get the path for each stock file in a list

list_files = (glob.glob("\\SMA_Analysis\\Stocks\\*.csv"))

# You can use this line to limit the analysis to a portion of the stocks in the "stocks folder"

# list_files = list_files[:100]

# Create the dataframe that we will be adding the final analysis of each stock to

Compare_Stocks = pd.DataFrame(columns=["Company", "Days_Observed", "Crosses", "True_Positive", "False_Positive", "True_Negative", "False_Negative", "Sensitivity",

"Specificity", "Accuracy", "TPR", "FPR"])

# While loop to cycle through the stock paths

count = 0

for stock in list_files:

# Dataframe to hold the historical data of the stock we are interested in.

Hist_data = pd.read_csv(stock)

Company = ((os.path.basename(stock)).split(".csv")[0]) # Name of the company

# Constants for the stock that we will be updating later

Days_Observed = 0

Crosses = 0

True_Positive = 0

False_Positive = 0

True_Negative = 0

False_Negative = 0

Sensitivity = 0

Specificity = 0

Accuracy = 0

# This list holds the closing prices of a stock

prices = []

c = 0

# Add the closing prices to the prices list and make sure we start at greater than 2 dollars to reduce outlier calculations.

while c < len(Hist_data):

if Hist_data.iloc[c,4] > float(2.00): # Check that the closing price for this day is greater than $2.00

prices.append(Hist_data.iloc[c,4])

c += 1

prices_df = pd.DataFrame(prices) # Make a dataframe from the prices list

# Calculate exponentiall weighted moving averages:

day12 = prices_df.ewm(span=12).mean() #

day26 = prices_df.ewm(span=26).mean()

macd = [] # List to hold the MACD line values

counter=0 # Loop to substantiate the MACD line

while counter < (len(day12)):

macd.append(day12.iloc[counter,0] - day26.iloc[counter,0]) # Subtract the 26 day EW moving average from the 12 day.

counter += 1

macd_df = pd.DataFrame(macd)

signal_df = macd_df.ewm(span=9).mean() # Create the signal line, which is a 9 day EW moving average

signal = signal_df.values.tolist() # Add the signal line values to a list.

# Loop to Compare the expected MACD crosses results to the actual results

Day = 1

while Day < len(macd)-5: # -1 to be able to use the last day for prediction, -5 so we can look at the 5 day post average.

Prev_Day = Day-1

# Avg_Closing_Next_Days = (prices[Day+1] + prices[Day+2] + prices[Day+3] + prices[Day+4] + prices[Day+5])/5 # To use 5 day average as a decision.

Avg_Closing_Next_Days = (prices[Day+1] + prices[Day+2] + prices[Day+3])/3 # To use 3 day average as a decision.

Days_Observed += 1 # Count how many days were observed

if ((signal[Prev_Day] > macd[Prev_Day]) and (signal[Day] <= macd[Day])): # when the signal line dips below the macd line (Expected increase over the next x days)

Crosses += 1 # register that a cross occurred

if (prices[Day] < Avg_Closing_Next_Days): # Tests if the price increases over the next x days.

True_Positive += 1

else:

False_Negative += 1

if ((signal[Prev_Day] < macd[Prev_Day]) and (signal[Day] >= macd[Day])): # when the signal line moves above the macd line (Expected dip over the next x days)

Crosses += 1

if (prices[Day] > Avg_Closing_Next_Days): # Tests if the price decreases over the next x days.

True_Negative += 1

else:

False_Positive += 1

Day += 1

try:

Sensitivity = (True_Positive / (True_Positive + False_Negative)) # Calculate sensitivity

except ZeroDivisionError: # Catch the divide by zero error

Sensitivity = 0

try:

Specificity = (True_Negative / (True_Negative + False_Positive)) # Calculate specificity

except ZeroDivisionError:

Specificity

try:

Accuracy = (True_Positive + True_Negative) / (True_Negative + True_Positive + False_Positive + False_Negative) # Calculate accuracy

except ZeroDivisionError:

Accuracy = 0

TPR = Sensitivity # Calculate the true positive rate

FPR = 1 - Specificity # Calculate the false positive rate

# Create a row to add to the compare_stocks

add_row = {'Company' : Company, 'Days_Observed' : Days_Observed, 'Crosses' : Crosses, 'True_Positive' : True_Positive, 'False_Positive' : False_Positive,

'True_Negative' : True_Negative, 'False_Negative' : False_Negative, 'Sensitivity' : Sensitivity, 'Specificity' : Specificity, 'Accuracy' : Accuracy, 'TPR' : TPR, 'FPR' : FPR}

Compare_Stocks = Compare_Stocks.append(add_row, ignore_index = True) # Add the analysis on the stock to the existing Compare_Stocks dataframe

count += 1

Compare_Stocks.to_csv("\\SMA_Analysis\\All_Stocks.csv", index = False) # Save the compiled data on each stock to a csv - All_Stocks.csv

股票排名

既然,我们已经掌握了,MACD指标如何预测单个股票的未来表现的完整理念,那么我们就可以开始进行排名。为此,我们打开上面创建的文件,然后将记录,保存到新的数据框中。在按照准确度,对他们进行排名后,我们对股票进行排序,然后将其保存为新的CSV。现在,我们有了按MACD技术指标预测的能力排名的股票清单。

Compare_Stocks = pd.read_csv("\\SMA_Analysis\\All_Stocks.csv") # Read in the All_Stocks data to a dataframe

# Delete companies that don't have enough crosses observed. I am using 50 crosses as my cuttoff:

Not_Enough_Records = []

Row = 0

while Row < (len(Compare_Stocks)):

if Compare_Stocks.iloc[Row, 2] < 50:

Not_Enough_Records.append(Row)

Row += 1

Compare_Stocks = Compare_Stocks.drop(Not_Enough_Records) # Remove records that do not have enough crosses for us to observe

Avg_Accuracy = [] # List to hold the accuracy of each stock

i=0

while i < (len(Compare_Stocks)):

Avg_Accuracy.append(Compare_Stocks.iloc[i,9])

i += 1

# Create a dataframe from Compare_Stocks

df = Compare_Stocks[['Company','Days_Observed', 'Crosses', 'True_Positive', 'False_Positive', 'True_Negative', 'False_Negative', 'Sensitivity', 'Specificity', 'TPR', 'FPR', 'Accuracy']]

df["Companies_Ranked"] = df["Accuracy"].rank(ascending = False) # Rank the stocks by their Accuracy

df.sort_values("Accuracy", inplace = True, ascending = False) # Sort the ranked stocks

df.to_csv("\\SMA_Analysis\\5_Day_Avg_26_12_MACD.csv", index = False) # Save the dataframe to a csv

# We now have a list of stocks ranked by how well the MACD indicator predicts their price change.

print("The average accuracy of all stocks observed: " + str(mean(Avg_Accuracy))) # The overall accuracy of the MACD.

解释结果

完全执行此代码后,您将看到一条打印出来的线,指出了总体准确性。 这是观察到的所有股票的平均准确性。 在我运行这段代码的时候,通常结果是47%-49%。 这应该让人感到震惊,因为这意味着盲目地使用MACD指标交易股票在统计上不如掷硬币准确。

幸运的是,该代码按其MACD准确性对股票进行排名,并显示观察到的交叉数量。 因此,投资者可以确定最佳库存和使用策略。 例如,如果使用MACD交易特定股票的历史准确性为40%,则采取与MACD建议相反的做法可能会有所帮助。

希望本文和代码对您有所帮助。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值