Feature Request: Heikin Ashi plotting
Is your feature request related to a problem? Please describe. I think the library is really impressive but there is a huge lack: it's not possible to plot Heikin Ashi candles...
Describe the solution you'd like I hope Heikin Ashi candles will be implemented soon...
Describe alternatives you've considered I tried to pre-compute the DataFrame for columns OHLC from the standard candlestick to Heikin Ashi candles but the library crashes because the candles values are unexpected in the library, so actually I need to plot Heikin Ashi but I'm not able to achieve this by using this library.
Additional context Could you provide me with feedback on this functionality implementation? Thanks!
Can you please show your code for computing Heikin Ashi, and exactly how you used that data to call mplfinance.plot() etc. It seems odd that it would "crash." Please also provide the complete traceback that gets output when the code "crashes." Please also include your input data as a csv file.
With you code and data as an example, we will consider whether to include Heikin Ashi as an available type in mplfinance.
Yes, sure. Here is the code:
import pandas as pd import pandas_ta as ta import ccxt import mplfinance as mpf import heikin_ashi as ha pd.set_option("display.max_rows", None) pd.set_option("display.max_columns", None) pd.set_option("display.expand_frame_repr", False) df = pd.DataFrame(ccxt.binance().fetch_ohlcv("BTC/USDT", "1m", limit=50), columns=["timestamp", "open", "high", "low", "close", "volume"]) df["timestamp"] = pd.to_datetime(df["timestamp"], unit="ms") df_s = ha.kline_to_df(df) ha_df = ha.heikin_ashi(df_s) df_s["EMA10"] = ta.ema(df_s["close"], length=10) df_s["EMA30"] = ta.ema(df_s["close"], length=30) re = pd.concat([df_s, ha_df], axis=1) re["open"] = re["HA-open"] re["high"] = re["HA-high"] re["low"] = re["HA-low"] re["close"] = re["HA-close"] print(re) style = mpf.make_mpf_style(base_mpf_style="charles") mpf.plot(re, type="candle", style=style, title="Test")
here is the Heikin_Ashi code: import pandas as pd
def kline_to_df(arr) -> pd.DataFrame: kline = pd.DataFrame( arr, columns=["timestamp", "open", "high", "low", "close", "volume"]) kline.index = pd.to_datetime(kline.timestamp, unit="ms") #kline.drop("timestamp", axis=1, inplace=True) return kline
def heikin_ashi(df, columnspar=["HA-open", "HA-high", "HA-low", "HA-close"]): heikin_ashi_df = pd.DataFrame(index=df.index.values, columns=columnspar)
heikin_ashi_df[columnspar[3]] = (df["open"] + df["high"] + df["low"] + df["close"]) / 4
for i in range(len(df)):
if i == 0:
heikin_ashi_df.iat[0, 0] = df["open"].iloc[0]
else:
heikin_ashi_df.iat[i, 0] = (heikin_ashi_df.iat[i-1, 0] + heikin_ashi_df.iat[i-1, 3]) / 2
heikin_ashi_df[columnspar[1]] = heikin_ashi_df.loc[:, [columnspar[0], columnspar[3]]].join(df["high"]).max(axis=1)
heikin_ashi_df[columnspar[2]] = heikin_ashi_df.loc[:, [columnspar[0], columnspar[3]]].join(df["low"]).min(axis=1)
return heikin_ashi_df
and finally here is the dataframe obtained: timestamp open high low close volume EMA10 EMA30 HA-open HA-high HA-low HA-close 2021-11-15 12:57:00 2021-11-15 12:57:00 65749.97 65749.980000 65693.500000 65730.9475 121.15118 NaN NaN 65749.97 65749.980000 65693.500000 65730.9475 2021-11-15 12:58:00 2021-11-15 12:58:00 65740.45875 65740.458750 65697.690000 65714.0150 24.38660 NaN NaN 65740.45875 65740.458750 65697.690000 65714.0150 2021-11-15 12:59:00 2021-11-15 12:59:00 65727.236875 65727.236875 65649.280000 65677.5425 117.36866 NaN NaN 65727.236875 65727.236875 65649.280000 65677.5425 2021-11-15 13:00:00 2021-11-15 13:00:00 65702.389688 65702.389688 65634.300000 65652.4175 44.34793 NaN NaN 65702.389688 65702.389688 65634.300000 65652.4175 2021-11-15 13:01:00 2021-11-15 13:01:00 65677.403594 65685.200000 65648.980000 65666.5775 112.19109 NaN NaN 65677.403594 65685.200000 65648.980000 65666.5775 2021-11-15 13:02:00 2021-11-15 13:02:00 65671.990547 65700.000000 65671.990547 65691.5725 43.55642 NaN NaN 65671.990547 65700.000000 65671.990547 65691.5725 2021-11-15 13:03:00 2021-11-15 13:03:00 65681.781523 65729.720000 65681.781523 65714.1775 40.48248 NaN NaN 65681.781523 65729.720000 65681.781523 65714.1775 2021-11-15 13:04:00 2021-11-15 13:04:00 65697.979512 65727.000000 65676.580000 65707.6425 44.05381 NaN NaN 65697.979512 65727.000000 65676.580000 65707.6425 2021-11-15 13:05:00 2021-11-15 13:05:00 65702.811006 65750.000000 65672.310000 65699.5425 130.28645 NaN NaN 65702.811006 65750.000000 65672.310000 65699.5425 2021-11-15 13:06:00 2021-11-15 13:06:00 65701.176753 65744.440000 65675.870000 65706.9850 134.86953 65695.798000 NaN 65701.176753 65744.440000 65675.870000 65706.9850 2021-11-15 13:07:00 2021-11-15 13:07:00 65704.080876 65740.000000 65683.790000 65713.7025 50.34336 65696.429273 NaN 65704.080876 65740.000000 65683.790000 65713.7025 2021-11-15 13:08:00 2021-11-15 13:08:00 65708.891688 65708.891688 65667.440000 65683.5375 30.74153 65691.160314 NaN 65708.891688 65708.891688 65667.440000 65683.5375 2021-11-15 13:09:00 2021-11-15 13:09:00 65696.214594 65696.214594 65658.690000 65679.1900 17.45790 65691.914802 NaN 65696.214594 65696.214594 65658.690000 65679.1900 2021-11-15 13:10:00 2021-11-15 13:10:00 65687.702297 65755.230000 65687.702297 65724.0375 122.04723 65702.533929 NaN 65687.702297 65755.230000 65687.702297 65724.0375 2021-11-15 13:11:00 2021-11-15 13:11:00 65705.869899 65760.000000 65705.869899 65749.7200 27.12870 65711.595033 NaN 65705.869899 65760.000000 65705.869899 65749.7200 2021-11-15 13:12:00 2021-11-15 13:12:00 65727.794949 65755.880000 65690.050000 65732.0750 145.55757 65714.941391 NaN 65727.794949 65755.880000 65690.050000 65732.0750 2021-11-15 13:13:00 2021-11-15 13:13:00 65729.934975 65750.000000 65729.934975 65739.9975 35.66777 65721.315683 NaN 65729.934975 65750.000000 65729.934975 65739.9975 2021-11-15 13:14:00 2021-11-15 13:14:00 65734.966237 65750.000000 65734.480000 65744.2200 25.20989 65725.149195 NaN 65734.966237 65750.000000 65734.480000 65744.2200 2021-11-15 13:15:00 2021-11-15 13:15:00 65739.593119 65749.000000 65694.190000 65719.9450 22.41653 65719.522069 NaN 65739.593119 65749.000000 65694.190000 65719.9450 2021-11-15 13:16:00 2021-11-15 13:16:00 65729.769059 65729.769059 65650.000000 65677.8050 26.99629 65711.032602 NaN 65729.769059 65729.769059 65650.000000 65677.8050 2021-11-15 13:17:00 2021-11-15 13:17:00 65703.78703 65703.787030 65633.330000 65655.5600 42.36497 65698.479402 NaN 65703.78703 65703.787030 65633.330000 65655.5600 2021-11-15 13:18:00 2021-11-15 13:18:00 65679.673515 65679.673515 65629.990000 65641.8200 53.54696 65686.028601 NaN 65679.673515 65679.673515 65629.990000 65641.8200 2021-11-15 13:19:00 2021-11-15 13:19:00 65660.746757 65660.746757 65605.650000 65621.4100 14.81129 65674.021583 NaN 65660.746757 65660.746757 65605.650000 65621.4100 2021-11-15 13:20:00 2021-11-15 13:20:00 65641.078379 65641.078379 65571.420000 65597.3150 39.38295 65655.368568 NaN 65641.078379 65641.078379 65571.420000 65597.3150 2021-11-15 13:21:00 2021-11-15 13:21:00 65619.196689 65619.196689 65550.000000 65576.3750 39.89877 65642.405192 NaN 65619.196689 65619.196689 65550.000000 65576.3750 2021-11-15 13:22:00 2021-11-15 13:22:00 65597.785845 65617.640000 65584.060000 65596.3425 25.89010 65634.622430 NaN 65597.785845 65617.640000 65584.060000 65596.3425 2021-11-15 13:23:00 2021-11-15 13:23:00 65597.064172 65617.640000 65597.064172 65604.2075 29.47369 65628.327442 NaN 65597.064172 65617.640000 65597.064172 65604.2075 2021-11-15 13:24:00 2021-11-15 13:24:00 65600.635836 65633.990000 65599.990000 65611.3075 18.30227 65625.222453 NaN 65600.635836 65633.990000 65599.990000 65611.3075 2021-11-15 13:25:00 2021-11-15 13:25:00 65605.971668 65621.610000 65567.700000 65596.2275 18.23573 65617.792916 NaN 65605.971668 65621.610000 65567.700000 65596.2275 2021-11-15 13:26:00 2021-11-15 13:26:00 65601.099584 65601.099584 65570.870000 65579.0300 14.19629 65609.263295 65670.856667 65601.099584 65601.099584 65570.870000 65579.0300 2021-11-15 13:27:00 2021-11-15 13:27:00 65590.064792 65590.064792 65564.150000 65567.5175 9.70177 65601.064514 65663.973656 65590.064792 65590.064792 65564.150000 65567.5175 2021-11-15 13:28:00 2021-11-15 13:28:00 65578.791146 65578.791146 65543.400000 65555.1325 14.31602 65591.560057 65656.542452 65578.791146 65578.791146 65543.400000 65555.1325 2021-11-15 13:29:00 2021-11-15 13:29:00 65566.961823 65568.560000 65512.010000 65536.9650 37.08175 65578.276410 65647.636488 65566.961823 65568.560000 65512.010000 65536.9650 2021-11-15 13:30:00 2021-11-15 13:30:00 65551.963412 65568.640000 65484.340000 65534.1075 64.26550 65575.855245 65642.302521 65551.963412 65568.640000 65484.340000 65534.1075 2021-11-15 13:31:00 2021-11-15 13:31:00 65543.035456 65570.880000 65542.160000 65558.1175 17.29590 65571.967018 65636.635906 65543.035456 65570.880000 65542.160000 65558.1175 2021-11-15 13:32:00 2021-11-15 13:32:00 65550.576478 65555.830000 65462.820000 65519.5800 37.89043 65559.827561 65628.156171 65550.576478 65555.830000 65462.820000 65519.5800 2021-11-15 13:33:00 2021-11-15 13:33:00 65535.078239 65535.078239 65458.560000 65487.6925 18.40686 65542.840731 65617.720289 65535.078239 65535.078239 65458.560000 65487.6925 2021-11-15 13:34:00 2021-11-15 13:34:00 65511.385369 65511.385369 65412.490000 65439.9175 44.56399 65519.480598 65604.600270 65511.385369 65511.385369 65412.490000 65439.9175 2021-11-15 13:35:00 2021-11-15 13:35:00 65475.651435 65475.651435 65390.000000 65418.2250 50.58628 65498.567762 65591.687994 65475.651435 65475.651435 65390.000000 65418.2250 2021-11-15 13:36:00 2021-11-15 13:36:00 65446.938217 65446.938217 65388.910000 65411.4475 21.68136 65483.277260 65580.254575 65446.938217 65446.938217 65388.910000 65411.4475 2021-11-15 13:37:00 2021-11-15 13:37:00 65429.192859 65444.160000 65400.940000 65425.1475 10.92630 65475.594122 65571.271700 65429.192859 65444.160000 65400.940000 65425.1475 2021-11-15 13:38:00 2021-11-15 13:38:00 65427.170179 65474.640000 65427.170179 65454.0600 17.91372 65473.733372 65564.438687 65427.170179 65474.640000 65427.170179 65454.0600 2021-11-15 13:39:00 2021-11-15 13:39:00 65440.61509 65484.520000 65430.100000 65464.1600 19.25854 65474.263668 65558.774901 65440.61509 65484.520000 65430.100000 65464.1600 2021-11-15 13:40:00 2021-11-15 13:40:00 65452.387545 65512.000000 65452.387545 65478.0275 22.40166 65471.986638 65552.514584 65452.387545 65512.000000 65452.387545 65478.0275 2021-11-15 13:41:00 2021-11-15 13:41:00 65465.207522 65486.530000 65395.580000 65443.0125 29.78677 65464.027249 65544.494934 65465.207522 65486.530000 65395.580000 65443.0125 2021-11-15 13:42:00 2021-11-15 13:42:00 65454.110011 65454.110011 65381.390000 65408.1800 21.90431 65450.515022 65534.508809 65454.110011 65454.110011 65381.390000 65408.1800 2021-11-15 13:43:00 2021-11-15 13:43:00 65431.145006 65431.145006 65350.560000 65387.0550 33.80941 65440.205018 65525.431466 65431.145006 65431.145006 65350.560000 65387.0550 2021-11-15 13:44:00 2021-11-15 13:44:00 65409.100003 65454.980000 65393.800000 65424.3900 14.70997 65442.891378 65520.886211 65409.100003 65454.980000 65393.800000 65424.3900 2021-11-15 13:45:00 2021-11-15 13:45:00 65416.745001 65476.990000 65416.745001 65458.2475 15.32926 65444.282037 65516.347745 65416.745001 65476.990000 65416.745001 65458.2475 2021-11-15 13:46:00 2021-11-15 13:46:00 65437.496251 65456.790000 65437.496251 65447.4150 5.86848 65443.928939 65511.573052 65437.496251 65456.790000 65437.496251 65447.4150
and the results of the error trace:
Traceback (most recent call last):
File "", line 22, in
thank you
Thanks. Before I look into this in any more detail, based on the final error message
File "D:\Tana\venv\lib\site-packages\mplfinance\_utils.py", line 49, in _check_input
o = np.where(np.isnan(opens))[0]
TypeError: ufunc 'isnan' not supported for the input types, and the inputs could not be safely coerced to any supported types according to the casting rule ''safe''
I would suggest you check and confirm that the numeric colums (especially open,high,low,close) are actually float types and not string types. If they are strings you can convert them using df = df.astype(float) or some variation (column by column) thereof.
Let me know, and if that is not the issue then I will look into this further. Once we resolve your immediate TypeError problem, I will consider whether or not to add Heikin Ashi as a type in mpf.plot().
Thanks Daniel! It works!
I used the following approach to convert data into floats:
re["open"] = re["HA-open"]
re["high"] = re["HA-high"]
re["low"] = re["HA-low"]
re["close"] = re["HA-close"]
re["open"] = pd.to_numeric(re["open"], downcast="float")
re["high"] = pd.to_numeric(re["high"], downcast="float")
re["low"] = pd.to_numeric(re["low"], downcast="float")
re["close"] = pd.to_numeric(re["close"], downcast="float")
Can we please have Heikin Ashi as type to this API?
Heikin Ashi as type to this API?
sounds doable too.. maybe as a util package?
I have code already working for Heiken-Ashi plot using mplfinance. I have not made it public yet. I will make it public hopefully next week.
Actually, here is a simple way to do it using the existing mplfinance:
Suppose I have a normal DatetimeIndex OHLC(V) dataframe (as mplfinance normally expects) called df, for example:
print(df.head(3))
Open High Low Close Volume
Datetime
2023-01-19 389.359985 390.429993 387.260010 388.600006 34612851
2023-01-20 390.100006 392.480011 388.380005 391.839996 41191178
2023-01-23 396.720001 402.109985 395.720001 401.500000 40128103
I can then plot Heikin-Ashi using mplfinance as follows:
ha_df = heikin_ashi(df)
mpf.plot(ha_df, type='candle', columns=['HAOpen','HAHigh','HALow','HAClose','Volume'])
where the function heikin_ashi(df) is defined as follows:
def heikin_ashi(df):
'''
Given a DataFrame `df` with a Pandas.DatetimeIndex and (at least the following)
columns "Open", "High", "Low", and "Close", this function will construct and return a
DataFrame of Heikin Ashi candles w/columns "HAOpen", "HAHigh", "HALow", and "HAClose"
'''
ha_close = (df['Open'] + df['High'] + df['Low'] + df['Close'])/4
ha_df = pd.DataFrame(dict(HAClose=ha_close))
ha_df['HAOpen'] = [0.0]*len(df)
# "seed" the first open:
prekey = df.index[0]
ha_df.at[prekey,'HAOpen'] = df.at[prekey,'Open']
# calculate the rest
for key in df.index[1:]:
ha_df.at[key,'HAOpen'] = (ha_df.at[prekey,'HAOpen'] + ha_df.at[prekey,'HAClose']) / 2.0
prekey = key
ha_df['HAHigh'] = pd.concat([ha_df.HAOpen,df.High],axis=1).max(axis=1)
ha_df['HALow'] = pd.concat([ha_df.HAOpen,df.Low ],axis=1).min(axis=1)
return ha_df
Those of you who don't want to wait for this to be integrated and released inside of mplfinance, you can use the above code.