Como se define aquí, el indicador de presagio de Hindenburg es:
El número diario de nuevos máximos de 52 semanas y mínimos de 52 semanas en un índice bursátil es mayor que una cantidad límite (típicamente 2.2%).
Para mí, significa que avanzamos diariamente y miramos hacia atrás 52 semanas o 252 días hábiles/de negociación, luego contamos la cantidad de máximos (o mínimos) y finalmente calculamos el rendimiento de eso o pct_change, que es la proporción de nuevos máximos (o mínimos) ) que quieren monitorear, por ejemplo, estar por encima del 2.2%
import pandas as pd import numpy as np import yfinance as yf # download the S&P500 df = yf.download('^GSPC') # compute the "highs" and "lows" df['Highs'] = df['Close'].rolling(252).apply(lambda x: x.cummax().diff(). apply(lambda x: np.where(x > 0, 1, 0)).sum()).pct_change() df['Lows'] = df['Close'].rolling(252).apply(lambda x: x.cummin().diff(). apply(lambda x: np.where(x < 0, 1, 0)).sum()).pct_change()¿Lo entendimos de la misma manera? ¿Hay una mejor manera de hacerlo?
¡Interesante pregunta! ¿Podría sugerir el siguiente código? Se ejecuta mucho más rápido que la solución de apply porque está vectorizado y también presenta los pasos un poco más claramente para que pueda inspeccionar los resultados intermedios.
Obtuve un resultado diferente a su código: puede comparar también trazando su resultado en la serie temporal en la parte inferior.
import pandas as pd import numpy as np import yfinance as yf # download the S&P500 df = yf.download('^GSPC') # Constants n_trading_day_window = 252 # Simplify the input dataframe to only the relevant column df_hin_omen = df[['Close']] # Calculate rolling highs and lows df_hin_omen.insert(1, 'rolling_high', df_hin_omen['Close'].rolling(n_trading_day_window).max()) df_hin_omen.insert(2, 'rolling_low', df_hin_omen['Close'].rolling(n_trading_day_window).min()) # High and low are simply when the given row matches the 252 day high or low df_hin_omen.insert(3, 'is_high', df_hin_omen.Close == df_hin_omen.rolling_high) df_hin_omen.insert(4, 'is_low', df_hin_omen.Close == df_hin_omen.rolling_low) # Calculate rolling percentages df_hin_omen.insert(5, 'percent_highs', df_hin_omen.is_high.rolling(n_trading_day_window).sum() / n_trading_day_window) df_hin_omen.insert(6, 'percent_lows', df_hin_omen.is_low.rolling(n_trading_day_window).sum() / n_trading_day_window)Una vez que haya ejecutado esto, puede inspeccionar los resultados de la siguiente manera:
import matplotlib, matplotlib.pyplot as plt fig, ax = plt.subplots(figsize=(16, 6)) df_hin_omen.resample('w').mean().percent_highs.plot(ax=ax) df_hin_omen.resample('w').mean().percent_lows.plot(ax=ax)De la Definición del Presagio de Hindenburg , "El Presagio de Hindenburg busca una desviación estadística de la premisa de que, en condiciones normales, algunas acciones están alcanzando nuevos máximos de 52 semanas o nuevos mínimos de 52 semanas. Sería anormal si ambos estuvieran ocurriendo en el Mismo tiempo."
Entonces, al mirar nuestro gráfico, mi interpretación es que el mercado de valores actualmente está cerrando en muchos máximos de 52 semanas, pero no muestra muchos mínimos de 52 semanas. Tenga en cuenta también que el artículo citado afirma que "se informó que había predicho correctamente una caída significativa del mercado de valores solo el 25% del tiempo". así que no estoy seguro si podemos leer demasiado en esto...
Editar
Eché un vistazo a su código y no creo que el uso de la función pct_change sea correcto; eso calculará el cambio en el diferencial móvil, por lo que un movimiento de, por ejemplo, 0.10% a 0.11% en realidad equivaldría a un 10% de cambio. En su lugar, desea la suma acumulada durante el último año y dividirla por la cantidad de días en el año, según mi código anterior.