无法通过 python pandas 计算 MACD

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/38270524/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-14 01:32:45  来源:igfitidea点击:

cannot calculate MACD via python pandas

pythonpandas

提问by Excaliburst

I have made a script to get stock-info for a list of stocks. For the stocks involved (groups in groupby), I need to calculate MACD.

我制作了一个脚本来获取股票列表的股票信息。对于所涉及的股票(groupby 中的组),我需要计算 MACD。

So as to not mix the price for one stock with the other I use a pandas groupby.

为了不将一只股票的价格与另一只股票的价格混在一起,我使用了 Pandas groupby。

# -*- coding: utf-8 -*-

import pandas as pd
from pandas.io.data import DataReader
import numpy as np
import time
from io import StringIO

runstart = time.time()     # Start script timer

stocklist = ['nflx','mmm'] 
tickers =   []
days_backtest=102  # MA98 kr?ver 102 d for at virke!
end = pd.Timestamp.utcnow()
start = end - days_backtest * pd.tseries.offsets.BDay()

    # Fetch stockinfo
def GetStock(stocklist, start, end, csv_file_all='alltickers_ohlc.csv'):
    '''
    Fetches stock-info for analysis of each ticker in stocklist
    '''
    print('\nGetting Stock-info from Yahoo-Finance')
    for ticker in stocklist:
        r = DataReader(ticker, "yahoo",
                       start = start, end = end)
        # add a symbol column
        r['Ticker'] = ticker
        tickers.append(r)
    # concatenate all the dfs
    df_all = pd.concat(tickers)

    # add col without space in adj close
    df_all['Adj_Close'] = df_all['Adj Close']
    #define df with the columns that i need             These can be put back in df_all
    df_all = df_all[['Ticker','Adj_Close','Volume']] #'Adj Close','Open','High','Low',

    # round to 2 dig.
#    df_all['Open'] = np.round(df_all['Open'], decimals=2)
#    df_all['High'] = np.round(df_all['High'], decimals=2)
#    df_all['Low'] = np.round(df_all['Low'], decimals=2)
#    df_all['Adj Close'] = np.round(df_all['Adj Close'], decimals=2)
    df_all['Adj_Close'] = np.round(df_all['Adj_Close'], decimals=2)

#    # Test the first 3 rows of each group for 'Difference' col transgress groups...
#    df_all_test = df_all.groupby('Ticker').head(27).reset_index().set_index('Date')
#    print ('\n df_all_test (27d summary from df) (Output)\n',df_all_test,'\n')

    # saving to a csv #
    df_all.reset_index().sort(['Ticker', 'Date'], ascending=[1,1]).set_index('Ticker').to_csv(csv_file_all, date_format='%Y/%m/%d')
#    df_all.sort_index(inplace=True)   # Sorts rows from date, mingling tickers - not wanted
    print('=========  Picked up new stockinfo   (df_all) \n')
#    print ('df_all.tail (Input)\n',df_all.tail(6),'\n')
    print(70 * '-')
#    print(df_all)

    return df_all

def moving_average(group, n=9, type='simple'):
    """
    compute an n period moving average.
    type is 'simple' | 'exponential'
    """
    group = np.asarray(df_['Adj_Close'])
    if type == 'simple':
        weights = np.ones(n)
    else:
        weights = np.exp(np.linspace(-1., 0., n))

    weights /= weights.sum()

    a = np.convolve(group, weights, mode='full')[:len(group)]
    a[:n] = a[n]
    return a
#    return pd.DataFrame({'MCD_Sign':a})

def moving_average_convergence(group, nslow=26, nfast=12):
    """
    compute the MACD (Moving Average Convergence/Divergence) using a fast and slow exponential moving avg'
    return value is emaslow, emafast, macd which are len(x) arrays
    """
    emaslow = moving_average(group, nslow, type='exponential')
    emafast = moving_average(group, nfast, type='exponential')
#    return emaslow, emafast, emafast - emaslow

    return pd.DataFrame({'emaSlw': emaslow,
                     'emaFst': emafast, 
                     'MACD': emafast - emaslow})


if __name__ == '__main__':

    ### Getstocks
    df_all = GetStock(stocklist, start, end)
    ### Sort DF
    df_all.reset_index().sort(['Ticker', 'Date'], ascending=[1,1]).set_index('Ticker')

    ### groupby screeener (filtering to only rel ticker group)
    df_ = df_all.set_index('Ticker', append=True)
    ''' Calculating all the KPIs via groupby (filtering pr ticker)'''
    grouped = df_.groupby(level=1).Adj_Close    
    nslow = 26
    nfast = 12
    nema = 9

    df_[['emaSlw', 'emaFst', 'MACD']] = df_.groupby(level=1).Adj_Close.apply(moving_average_convergence)
    df_['MCD_Sign'] = df_.groupby(level=1).Adj_Close.apply(moving_average)

    print ('(Output df)\n',df_,'\n')

    df = df_.reset_index('Ticker')    
    # Test the last row of each group for new numbers pr group...
    df_test = df.groupby('Ticker').tail(1).reset_index().set_index('Date')
    print ('df_test (summary from df) (Output)\n',df_test,'\n')

Apparantly I get no results in the columns for all MACD numbers. So somewhere the calculation goes south. I have no clue as to what is going wrong...

显然,我在所有 MACD 数字的列中都没有得到结果。所以在某处计算向南。我不知道出了什么问题......

The output line pr stock-ticker:

输出行 pr 股票行情:

df_test (summary from df) (Output)
            Ticker  Adj_Close   Volume  emaSlw  emaFst  MACD MCD_Sign
Date                                                                
2016-07-07   nflx      95.10  9902700     NaN     NaN   NaN      NaN
2016-07-07    mmm     174.87  1842300     NaN     NaN   NaN      NaN 

Any of you guys... A tip!?

你们中的任何人......提示!?

回答by Grr

So it looks to me like you did more work than you really needed to here. The answer is a little simpler. You don't need to define your own moving average function, and this is in fact what is causing your problem.

所以在我看来,你做了比你真正需要的更多的工作。答案要简单一些。您不需要定义自己的移动平均函数,这实际上是导致您出现问题的原因。

Change moving_averageto:

更改moving_average为:

def moving_average(group, n=9):
    sma = pd.rolling_mean(group, n)
    return sma

Change moving_average_converganceto:

更改moving_average_convergance为:

def moving_average_convergence(group, nslow=26, nfast=12):
    emaslow = pd.ewma(group, span=nslow, min_periods=1)
    emafast = pd.ewma(group, span=nfast, min_periods=1)
    result = pd.DataFrame({'MACD': emafast-emaslow, 'emaSlw': emaslow, 'emaFst': emafast})
    return result

N.B. I have put 'MACD' first here because despite how you have it listed, the DataFrame reorders the columns alphabetically.

注意,我将“MACD”放在首位,因为不管您如何列出它,DataFrame 都会按字母顺序对列重新排序。

Finally change:

最后改变:

df_[['emaSlw', 'emaFst', 'MACD']] = df_.groupby(level=1).Adj_Close.apply(moving_average_convergence)

to:

到:

df_[['MACD', 'emaSlw', 'emaFst']] = df_.groupby(level=1).Adj_Close.apply(moving_average_convergence)

That should do it.

那应该这样做。