【问题标题】:Python/Pandas calculate Ichimoku chart componentsPython/Pandas 计算 Ichimoku 图表组件
【发布时间】:2015-04-13 04:10:40
【问题描述】:

我有 Pandas DataFrame 对象,其中包含日期、开盘、收盘、最低和最高每日股票数据。我想计算Ichimoku 图表的组成部分。我可以使用以下代码获取我的数据:

high_prices = data['High']
close_prices = data['Close']
low_prices = data['Low']
dates = data['Date']  # contains datetime objects

我需要计算以下系列(Ichimoku 称之为 Tenkan-Sen 线):

(9 周期高点 + 9 周期低点)/2

  • 9 期高点 = 过去 9 天的最高高点,
  • 9-period low = 最近 9 天的最低 Low 值, 所以两者都应该从第 9 天开始。

我找到了 R 语言 here 的解决方案,但我很难将其翻译成 Python/Pandas 代码。

Ichimoku 图表包含更多组件,但是当我知道如何在 Pandas 中计算 Tenkan-Sen 线时,我将能够计算所有组件(我将分享代码)。

【问题讨论】:

  • pd.rolling_max(high_prices, window = 9) 是否为您提供您正在寻找的 9 期高点和pd.rolling_min(low_prices, window = 9)
  • 是的,我不知道这些功能:)。熊猫真棒。谢谢。
  • 这是一个有效的 python/pandas 实现:github.com/kumotrader/ichimoku-crypto

标签: python pandas


【解决方案1】:

这是我的 Numba / Numpy 版本的 Ichimoku。您可以更改参数并计算未来的云。我不知道这个转变是否与tenkansen、kinjunsen或senkou b有关,但我把它放在一边,因为我懒得去发现。

import numpy as np
from numba import jit   

@jit(nopython=True)
def ichimoku_calc(data, period, shift=0):
    size = len(data)
    calc = np.array([np.nan] * (size + shift))
    for i in range(period - 1, size):
        window = data[i + 1 - period:i + 1]
        calc[i + shift] = (np.max(window) + np.min(window)) / 2
    return calc


@jit(nopython=True)
def ichimoku(data, tenkansen=9, kinjunsen=26, senkou_b=52, shift=26):
    size = len(data)
    n_tenkansen = ichimoku_calc(data, tenkansen)
    n_kinjunsen = ichimoku_calc(data, kinjunsen)
    n_chikou = np.concatenate(((data[shift:]), (np.array([np.nan] * (size - shift)))))
    n_senkou_a = np.concatenate((np.array([np.nan] * shift), ((n_tenkansen + n_kinjunsen) / 2)))
    n_senkou_b = ichimoku_calc(data, senkou_b, shift)
    return n_tenkansen, n_kinjunsen, n_chikou, n_senkou_a, n_senkou_b

您必须将输入数据转换为 numpy 数组,并确保您的最终时间索引长度为 len(data) + shift,并使用正确的时间步长计算期货日期。 Ichimoku 工作量很大...

我的交易机器人的结果:

Ichimoku on ETHUSDT pair

【讨论】:

    【解决方案2】:

    我对 @chilliq 的代码进行了更改,并制作了一个实时工作示例,该示例现在可以在 2021 年 7 月使用。为了使用实时数据,您需要以相反的顺序对其进行排序,以便最近的值不是 @987654321 @。

    def Ichimoku_Cloud(df):
            '''
            Get the values of Lines for Ichimoku Cloud
            args:
                df: Dataframe
            '''
            d = df.sort_index(ascending=False) # my Live NSE India data is in Recent -> Oldest order
    
            # Tenkan-sen (Conversion Line): (9-period high + 9-period low)/2))
            period9_high = d['HIGH'].rolling(window=9).max()
            period9_low = d['LOW'].rolling(window=9).min()
            tenkan_sen = (period9_high + period9_low) / 2
    
    
            # Kijun-sen (Base Line): (26-period high + 26-period low)/2))
            period26_high = d['HIGH'].rolling(window=26).max()
            period26_low = d['LOW'].rolling(window=26).min()
            kijun_sen = (period26_high + period26_low) / 2
    
            # Senkou Span A (Leading Span A): (Conversion Line + Base Line)/2))
            senkou_span_a = ((tenkan_sen + kijun_sen) / 2).shift(26)
    
            # Senkou Span B (Leading Span B): (52-period high + 52-period low)/2))
            period52_high = d['HIGH'].rolling(window=52).max()
            period52_low = d['LOW'].rolling(window=52).min()
            senkou_span_b = ((period52_high + period52_low) / 2).shift(26)
    
            # The most current closing price plotted 22 time periods behind (optional)
            chikou_span = d['CLOSE'].shift(-22) # Given at Trading View.
    
            d['blue_line'] = tenkan_sen
            d['red_line'] = kijun_sen
            d['cloud_green_line_a'] = senkou_span_a
            d['cloud_red_line_b'] = senkou_span_b
            d['lagging_line'] = chikou_span
            return d.sort_index(ascending=True)
    

    【讨论】:

      【解决方案3】:

      我不是财务专家或绘图专家,但以下显示了示例财务数据以及如何使用 rolling_maxrolling_min

      In [60]:
      
      import pandas.io.data as web
      import datetime
      start = datetime.datetime(2010, 1, 1)
      end = datetime.datetime(2013, 1, 27)
      data=web.DataReader("F", 'yahoo', start, end)
      high_prices = data['High']
      close_prices = data['Close']
      low_prices = data['Low']
      dates = data.index
      nine_period_high = df['High'].rolling(window=9).max()
      nine_period_low = df['Low'].rolling(window=9).min()
      ichimoku = (nine_period_high + nine_period_low) /2
      ichimoku
      Out[60]:
      Date
      2010-01-04       NaN
      2010-01-05       NaN
      2010-01-06       NaN
      2010-01-07       NaN
      2010-01-08       NaN
      2010-01-11       NaN
      2010-01-12       NaN
      2010-01-13       NaN
      2010-01-14    11.095
      2010-01-15    11.270
      2010-01-19    11.635
      2010-01-20    11.730
      2010-01-21    11.575
      2010-01-22    11.275
      2010-01-25    11.220
      ...
      2013-01-04    12.585
      2013-01-07    12.685
      2013-01-08    13.005
      2013-01-09    13.030
      2013-01-10    13.230
      2013-01-11    13.415
      2013-01-14    13.540
      2013-01-15    13.675
      2013-01-16    13.750
      2013-01-17    13.750
      2013-01-18    13.750
      2013-01-22    13.845
      2013-01-23    13.990
      2013-01-24    14.045
      2013-01-25    13.970
      Length: 771
      

      调用data[['High', 'Low', 'Close', 'ichimoku']].plot() 会产生以下情节:

      更新

      在@PedroLobito 的 cmets 指出不完整/不正确的公式后,我采用了 @chilliq 的答案并针对 pandas 0.16.1 及更高版本进行了修改:

      import pandas as pd
      from pandas_datareader import data, wb
      import datetime
      start = datetime.datetime(2010, 1, 1)
      end = datetime.datetime(2013, 1, 27)
      d=data.DataReader("F", 'yahoo', start, end)
      high_prices = d['High']
      close_prices = d['Close']
      low_prices = d['Low']
      dates = d.index
      nine_period_high =  df['High'].rolling(window=9).max()
      nine_period_low = df['Low'].rolling(window=9).min()
      d['tenkan_sen'] = (nine_period_high + nine_period_low) /2
      
      # Kijun-sen (Base Line): (26-period high + 26-period low)/2))
      period26_high = high_prices.rolling(window=26).max()
      period26_low = low_prices.rolling(window=26).min()
      d['kijun_sen'] = (period26_high + period26_low) / 2
      
      # Senkou Span A (Leading Span A): (Conversion Line + Base Line)/2))
      d['senkou_span_a'] = ((d['tenkan_sen'] + d['kijun_sen']) / 2).shift(26)
      
      # Senkou Span B (Leading Span B): (52-period high + 52-period low)/2))
      period52_high = high_prices.rolling(window=52).max()
      period52_low = low_prices.rolling(window=52).min()
      d['senkou_span_b'] = ((period52_high + period52_low) / 2).shift(26)
      
      # The most current closing price plotted 22 time periods behind (optional)
      d['chikou_span'] = close_prices.shift(-22) # 22 according to investopedia
      d.plot()
      

      导致以下情节,不清楚,因为如前所述,我不是金融专家:

      【讨论】:

      • 是的,这很简单。我担心我必须自己实现 rolling_min 和 rolling_max,但它已经存在了。再次感谢。
      • @PedroLobito 请解释为什么它是错误的,而不是仅仅留下简短的评论和反对
      • @EdChum 看看这个页面上的另一个答案,或者mql5.com/en/forum/16972,你就会明白为什么了。
      • @PedroLobito 查看更新的答案,情节不清楚,但公式与 OP 的答案相同,但已修改为添加为新列并更新为 pandas 版本 0.16.1 或更新由于 pandas datareader分离
      • 太棒了!现在公式是正确的。感谢您花时间更新它。 +1
      【解决方案4】:
      import mplfinance as mpf
      import pandas as pd
      
      #Import the data into a "df", with headers, with the name of the stock like "stk = 'AAPL'"
      #MPLFinance does not fill-in-between,hence there is no cloud.
      
      #Tenkan Sen
      tenkan_max = df['High'].rolling(window = 9, min_periods = 0).max()
      tenkan_min = df['Low'].rolling(window = 9, min_periods = 0).min()
      df['tenkan_avg'] = (tenkan_max + tenkan_min) / 2
      
      #Kijun Sen
      kijun_max = df['High'].rolling(window = 26, min_periods = 0).max()
      kijun_min = df['Low'].rolling(window = 26, min_periods = 0).min()
      df['kijun_avg'] = (kijun_max + kijun_min) / 2
      
      #Senkou Span A
      #(Kijun + Tenkan) / 2 Shifted ahead by 26 periods
      df['senkou_a'] = ((df['kijun_avg'] + df['tenkan_avg']) / 2).shift(26)
      
      #Senkou Span B
      #52 period High + Low / 2
      senkou_b_max = df['High'].rolling(window = 52, min_periods = 0).max()
      senkou_b_min = df['Low'].rolling(window = 52, min_periods = 0).min()
      df['senkou_b'] = ((senkou_b_max + senkou_b_min) / 2).shift(52)
      
      #Chikou Span
      #Current close shifted -26
      df['chikou'] = (df['Close']).shift(-26)
      
      
      #Plotting Ichimoku
      
      #m_plots = ['kijun_avg', 'tenkan_avg',df[df.columns[5:]][-250:] ]
      
      add_plots= [
                  mpf.make_addplot(df['kijun_avg'][-250:]),
                  mpf.make_addplot(df['tenkan_avg'][-250:]),
                  mpf.make_addplot(df['chikou'][-250:]),
                  mpf.make_addplot(df['senkou_a'][-250:]),
                  mpf.make_addplot(df['senkou_b'][-250:])
                 ]
      
      mpf.plot(df[-250:], type = 'candle', mav= 200, volume = True, ylabel = "Price", ylabel_lower  = 'Volume', style = 'nightclouds', figratio=(15,10), figscale = 1.5,  addplot = add_plots,  title = '%s' %stk)
      

      【讨论】:

        【解决方案5】:
        high_9 = pd.rolling_max(df.high, window= 9)
        low_9 =  pd.rolling_min(df.low, window= 9)
        df['conversion_line'] = (high_9 + low_9) /2
        
        high_26 = pd.rolling_max(df.high, window= 26)
        low_26 = pd.rolling_min(df.low, window= 26)
        df['base_line'] = (high_26 + low_26) / 2
        
        df['leading_span_A'] = ((df.conversion_line + df.base_line) / 2).shift(30)
        
        high_52 = pd.rolling_max(df.high, window= 52)
        low_52 = pd.rolling_min(df.high, window= 52)
        df['leading_span_B'] = ((high_52 + low_52) / 2).shift(30)
        
        df['lagging_span'] = df.close.shift(-30)
        
        fig,ax = plt.subplots(1,1,sharex=True,figsize = (20,9)) #share x axis and set a figure size
        ax.plot(df.index, df.close,linewidth=4) # plot Close with index on x-axis with a line thickness of 4
        
        
        # use the fill_between call of ax object to specify where to fill the chosen color
        # pay attention to the conditions specified in the fill_between call
        ax.fill_between(df.index,leading_span_A,df.leading_span_B,where = df.leading_span_A >= df.leading_span_B, color = 'lightgreen')
        ax.fill_between(df.index,df.leading_span_A,df.leading_span_B,where = leading_span_A < df.leading_span_B, color = 'lightcoral')
        

        【讨论】:

          【解决方案6】:

          EdChum 的答案在计算 Ichimoku Cloud 的组件时非常接近。

          这些方法是正确的,但它未能适应两个leading_spans 的未来日期。当我们将前导跨度移动 26 时,pandas 只会移动到最后一个日期或最后一个索引,并且忽略额外(或未来)的 26 值。

          这是一个适应未来日期或未来云形成的实现

          from datetime import timedelta
          
          high_9 = df['High'].rolling(window= 9).max()
          low_9 = df['Low'].rolling(window= 9).min()
          df['tenkan_sen'] = (high_9 + low_9) /2
          
          high_26 = df['High'].rolling(window= 26).max()
          low_26 = df['Low'].rolling(window= 26).min()
          df['kijun_sen'] = (high_26 + low_26) /2
          
          # this is to extend the 'df' in future for 26 days
          # the 'df' here is numerical indexed df
          last_index = df.iloc[-1:].index[0]
          last_date = df['Date'].iloc[-1].date()
          for i in range(26):
              df.loc[last_index+1 +i, 'Date'] = last_date + timedelta(days=i)
          
          df['senkou_span_a'] = ((df['tenkan_sen'] + df['kijun_sen']) / 2).shift(26)
          
          high_52 = df['High'].rolling(window= 52).max()
          low_52 = df['Low'].rolling(window= 52).min()
          df['senkou_span_b'] = ((high_52 + low_52) /2).shift(26)
          
          # most charting softwares dont plot this line
          df['chikou_span'] = df['Close'].shift(-22) #sometimes -26 
          
          tmp = df[['Close','senkou_span_a','senkou_span_b','kijun_sen','tenkan_sen']].tail(300)
          a1 = tmp.plot(figsize=(15,10))
          a1.fill_between(tmp.index, tmp.senkou_span_a, tmp.senkou_span_b)
          

          【讨论】:

          • 你(或其他人)能帮我理解这条线吗?对于范围内的 i (26):df.loc[last_index+1 +i, 'Date'] = last_date + timedelta(days=i)
          • 我遇到的问题是我的索引是日期时间索引,我没有名为“日期”的列
          • @Naveen,它显示了当前每日股价的奇怪图表。你确定这是正确的代码吗?
          【解决方案7】:

          我希望写 Ichimoku 书籍的人在计算中的指示更加明确。查看上面的代码,我假设如下:

          1. tenkan-sen:(9 周期最高高 + 9 周期最低低)/2 选择一个日期。寻找前九个时期的最高价。 寻找相同九个时期的最低低价。添加两个价格 一起除以二。在日期的 Y 轴上绘制结果。
          2. kiju-sen:(最高 26 周期 + 最低 26 周期)/2 使用与tenkan-sen 相同的日期。寻找最高的最高价格 前二十六期。寻找相同的最低低价 二十六期。将两个价格相加并除以二。将结果绘制在 日期的 Y 轴。
          3. chikou span:在 Y 轴上绘制 26 个周期的日期收盘价 在所选日期的左侧。
          4. senkou span A: (tenkan-sen + kiju-sen)/2 向右移动了 26 个句点。 从情节的最左侧日期开始。添加的值 Tenkan-sen 和 kiju-sen。将总和除以 2。将结果值绘制在 右边二十六个句点的日期。继续这个直到你到达 今天的日期。
          5. senkou span B:(52期最高最高价+52期最低最低价)/2 向右移动了 26 个句点。 再次从情节的最左侧日期开始。找到最高点 前 52 个时期的价格。求同款52的最低价 期间。将总和除以 2。将结果值绘制在 右边二十六个句点的日期。继续这个直到你到达 今天的日期。

          绘制从选定日期到今天日期的前三个结果为三行。最后两个给出了一个绘图区域(“云”)以及定义上/下“云”边界的两条可能的支撑/阻力线。所有这些都假设“周期”是日期(作为其他周期的示例,对于日间交易者来说,它们可能是 15 分钟周期)。此外,有些书有 senkou plan B 转移 26 个周期,有些转移它 22 个周期。我知道细田刚一的原著有二十六期,所以我使用了那个值。

          感谢您编写程序。虽然我认为我理解了关于这个主题的书籍的作者的意思,但直到我看到代码我才确定。显然,作者不是做证明的程序员或数学家。我想我太线性了!

          【讨论】:

            【解决方案8】:

            感谢之前的回答,有代码:

            # Tenkan-sen (Conversion Line): (9-period high + 9-period low)/2))
            period9_high = pd.rolling_max(high_prices, window=9)
            period9_low = pd.rolling_min(low_prices, window=9)
            tenkan_sen = (period9_high + period9_low) / 2
            
            # Kijun-sen (Base Line): (26-period high + 26-period low)/2))
            period26_high = pd.rolling_max(high_prices, window=26)
            period26_low = pd.rolling_min(low_prices, window=26)
            kijun_sen = (period26_high + period26_low) / 2
            
            # Senkou Span A (Leading Span A): (Conversion Line + Base Line)/2))
            senkou_span_a = ((tenkan_sen + kijun_sen) / 2).shift(26)
            
            # Senkou Span B (Leading Span B): (52-period high + 52-period low)/2))
            period52_high = pd.rolling_max(high_prices, window=52)
            period52_low = pd.rolling_min(low_prices, window=52)
            senkou_span_b = ((period52_high + period52_low) / 2).shift(26)
            
            # The most current closing price plotted 22 time periods behind (optional)
            chikou_span = close_prices.shift(-22) # 22 according to investopedia
            

            【讨论】:

            • 你几乎明白了你忘记在两个 senkou spans 中添加.shift(26),而你确实忘记了Chikou_Span = close_prices.shift(-26)
            • Chikou 是 -26 而不是 -22
            猜你喜欢
            • 2020-06-12
            • 1970-01-01
            • 2020-05-18
            • 1970-01-01
            • 1970-01-01
            • 2019-09-27
            • 1970-01-01
            • 1970-01-01
            • 2019-04-19
            相关资源
            最近更新 更多