Adaptive price zone (APZ)

Load basic packages
import pandas as pd
import numpy as np
import os
import gc
import copy
from pathlib import Path
from datetime import datetime, timedelta, time, date
#this package is to download equity price data from yahoo finance
#the source code of this package can be found here: https://github.com/ranaroussi/yfinance/blob/main
import yfinance as yf
pd.options.display.max_rows = 100
pd.options.display.max_columns = 100

import warnings
warnings.filterwarnings("ignore")

import pytorch_lightning as pl
random_seed=1234
pl.seed_everything(random_seed)
Global seed set to 1234





1234
#S&P 500 (^GSPC),  Dow Jones Industrial Average (^DJI), NASDAQ Composite (^IXIC)
#Russell 2000 (^RUT), Crude Oil Nov 21 (CL=F), Gold Dec 21 (GC=F)
#Treasury Yield 10 Years (^TNX)

#benchmark_tickers = ['^GSPC', '^DJI', '^IXIC', '^RUT',  'CL=F', 'GC=F', '^TNX']

benchmark_tickers = ['^GSPC']
tickers = benchmark_tickers + ['GSK', 'NVO', 'PFE', 'DAL']
#https://github.com/ranaroussi/yfinance/blob/main/yfinance/base.py
#     def history(self, period="1mo", interval="1d",
#                 start=None, end=None, prepost=False, actions=True,
#                 auto_adjust=True, back_adjust=False,
#                 proxy=None, rounding=False, tz=None, timeout=None, **kwargs):

dfs = {}

for ticker in tickers:
    cur_data = yf.Ticker(ticker)
    hist = cur_data.history(period="max", start='2000-01-01')
    print(datetime.now(), ticker, hist.shape, hist.index.min(), hist.index.max())
    dfs[ticker] = hist
2022-09-10 20:49:41.614294 ^GSPC (5710, 7) 1999-12-31 00:00:00 2022-09-09 00:00:00
2022-09-10 20:49:41.889554 GSK (5710, 7) 1999-12-31 00:00:00 2022-09-09 00:00:00
2022-09-10 20:49:42.253902 NVO (5710, 7) 1999-12-31 00:00:00 2022-09-09 00:00:00
2022-09-10 20:49:42.572385 PFE (5710, 7) 1999-12-31 00:00:00 2022-09-09 00:00:00
2022-09-10 20:49:42.818600 DAL (3867, 7) 2007-05-03 00:00:00 2022-09-09 00:00:00
ticker = 'DAL'
dfs[ticker].tail(5)
Open High Low Close Volume Dividends Stock Splits
Date
2022-09-02 31.440001 31.830000 30.700001 30.940001 8626500 0.0 0
2022-09-06 31.340000 31.650000 30.660000 31.190001 7630800 0.0 0
2022-09-07 31.290001 32.340000 31.270000 32.230000 9035900 0.0 0
2022-09-08 31.719999 32.490002 31.549999 32.119999 11085400 0.0 0
2022-09-09 32.430000 32.759998 32.240002 32.660000 10958900 0.0 0
Define APZ calculation function
Calculate APZ
df = dfs[ticker][['Open', 'High', 'Low', 'Close', 'Volume']]
df = df.round(2)
from core.finta import TA
TA.APZ
<function core.finta.TA.APZ(ohlc: pandas.core.frame.DataFrame, period: int = 21, dev_factor: int = 2, MA: pandas.core.series.Series = None, adjust: bool = True) -> pandas.core.frame.DataFrame>
df_ta = TA.APZ(df, period=14, dev_factor=2.2)
df = df.merge(df_ta, left_index = True, right_index = True, how='inner' )

del df_ta
gc.collect()
80
df_ta = TA.MAMA(df, column='close')
df = df.merge(df_ta, left_index = True, right_index = True, how='inner' )

del df_ta
gc.collect()
21
df_ta = TA.APZ(df, period=14, dev_factor=2.2, MA=df['MAMA'])
df_ta.columns = [f'MAMA_{c}' for c in df_ta.columns]
df = df.merge(df_ta, left_index = True, right_index = True, how='inner' )

df_ta = TA.APZ(df, period=14, dev_factor=2.2, MA=df['FAMA'])
df_ta.columns = [f'FAMA_{c}' for c in df_ta.columns]
df = df.merge(df_ta, left_index = True, right_index = True, how='inner' )

del df_ta
gc.collect()
0
display(df.head(5))
display(df.tail(5))
Open High Low Close Volume APZ_UPPER APZ_LOWER MAMA FAMA MAMA_APZ_UPPER MAMA_APZ_LOWER FAMA_APZ_UPPER FAMA_APZ_LOWER
Date
2007-05-03 19.32 19.50 18.25 18.40 8052800 21.150000 15.650000 18.40 18.40 21.150000 15.650000 21.150000 15.650000
2007-05-04 18.88 18.96 18.39 18.64 5437300 20.908929 16.267602 18.64 18.64 20.960663 16.319337 20.960663 16.319337
2007-05-07 18.83 18.91 17.94 18.08 2646300 20.493791 16.082627 18.08 18.08 20.285582 15.874418 20.285582 15.874418
2007-05-08 17.76 17.76 17.14 17.44 4166100 19.921244 15.746675 17.44 17.44 19.527285 15.352715 19.527285 15.352715
2007-05-09 17.54 17.94 17.44 17.58 7541100 19.640269 15.703611 17.58 17.58 19.548329 15.611671 19.548329 15.611671
Open High Low Close Volume APZ_UPPER APZ_LOWER MAMA FAMA MAMA_APZ_UPPER MAMA_APZ_LOWER FAMA_APZ_UPPER FAMA_APZ_LOWER
Date
2022-09-02 31.44 31.83 30.70 30.94 8626500 33.658708 29.756629 31.312376 32.321281 33.263416 29.361337 34.272320 30.370241
2022-09-06 31.34 31.65 30.66 31.19 7630800 33.478423 29.537191 31.251188 32.053757 33.221804 29.280572 34.024373 30.083141
2022-09-07 31.29 32.34 31.27 32.23 9035900 33.603018 29.618747 31.740594 31.975467 33.732730 29.748458 33.967602 29.983331
2022-09-08 31.72 32.49 31.55 32.12 11085400 33.681581 29.662285 31.930297 31.964174 33.939945 29.920649 33.973822 29.954526
2022-09-09 32.43 32.76 32.24 32.66 10958900 33.867567 29.852742 32.211529 32.011840 34.218942 30.204117 34.019253 30.004428
df[['APZ_UPPER',  'APZ_LOWER']].hist(bins=50)
array([[<AxesSubplot:title={'center':'APZ_UPPER'}>,
        <AxesSubplot:title={'center':'APZ_LOWER'}>]], dtype=object)

png

#https://github.com/matplotlib/mplfinance
#this package help visualize financial data
import mplfinance as mpf
import matplotlib.colors as mcolors

# all_colors = list(mcolors.CSS4_COLORS.keys())#"CSS Colors"
# all_colors = list(mcolors.TABLEAU_COLORS.keys()) # "Tableau Palette",
# all_colors = list(mcolors.BASE_COLORS.keys()) #"Base Colors",
all_colors = ['dodgerblue', 'firebrick','limegreen','skyblue','lightgreen',  'navy','yellow','plum',  'yellowgreen']
#https://github.com/matplotlib/mplfinance/issues/181#issuecomment-667252575
#list of colors: https://matplotlib.org/stable/gallery/color/named_colors.html
#https://github.com/matplotlib/mplfinance/blob/master/examples/styles.ipynb

def make_3panels2(main_data, add_data, mid_panel=None, chart_type='candle', names=None, figratio=(14,9)):
    """
    main chart type: default is candle. alternatives: ohlc, line

    example:
    start = 200

    names = {'main_title': 'MAMA: MESA Adaptive Moving Average', 
             'sub_tile': 'S&P 500 (^GSPC)', 'y_tiles': ['price', 'Volume [$10^{6}$]']}


    make_candle(df.iloc[-start:, :5], df.iloc[-start:][['MAMA', 'FAMA']], names = names)
    
    """

    style = mpf.make_mpf_style(base_mpf_style='yahoo',  #charles
                               base_mpl_style = 'seaborn-whitegrid',
#                                marketcolors=mpf.make_marketcolors(up="r", down="#0000CC",inherit=True),
                               gridcolor="whitesmoke", 
                               gridstyle="--", #or None, or - for solid
                               gridaxis="both", 
                               edgecolor = 'whitesmoke',
                               facecolor = 'white', #background color within the graph edge
                               figcolor = 'white', #background color outside of the graph edge
                               y_on_right = False,
                               rc =  {'legend.fontsize': 'small',#or number
                                      #'figure.figsize': (14, 9),
                                     'axes.labelsize': 'small',
                                     'axes.titlesize':'small',
                                     'xtick.labelsize':'small',#'x-small', 'small','medium','large'
                                     'ytick.labelsize':'small'
                                     }, 
                              )   

    if (chart_type is None) or (chart_type not in ['ohlc', 'line', 'candle', 'hollow_and_filled']):
        chart_type = 'candle'
    len_dict = {'candle':2, 'ohlc':3, 'line':1, 'hollow_and_filled':2}    
        
    kwargs = dict(type=chart_type, figratio=figratio, volume=True, volume_panel=1, 
                  panel_ratios=(4,2), tight_layout=True, style=style, returnfig=True)
    
    if names is None:
        names = {'main_title': '', 'sub_tile': ''}
    



    added_plots = { }
    for name_, data_ in add_data.iteritems():
        added_plots[name_] = mpf.make_addplot(data_, panel=0, width=1, secondary_y=False)
    
    fb_bbands_ = dict(y1=add_data.iloc[:, 0].values,
                      y2=add_data.iloc[:, 2].values,color="lightskyblue",alpha=0.1,interpolate=True)
    fb_bbands_['panel'] = 0
    

    fb_bbands= [fb_bbands_]
    
    
    if mid_panel is not None:
        i = 0
        for name_, data_ in mid_panel.iteritems():
            added_plots[name_] = mpf.make_addplot(data_, panel=1, color=all_colors[i])
            i = i + 1
        fb_bbands2_ = dict(y1=np.zeros(mid_panel.shape[0]),
                      y2=0.8+np.zeros(mid_panel.shape[0]),color="lightskyblue",alpha=0.1,interpolate=True)
        fb_bbands2_['panel'] = 1
        fb_bbands.append(fb_bbands2_)


    fig, axes = mpf.plot(main_data,  **kwargs,
                         addplot=list(added_plots.values()), 
                         fill_between=fb_bbands)
    # add a new suptitle
    fig.suptitle(names['main_title'], y=1.05, fontsize=12, x=0.1285)

    axes[0].legend([None]*5)
    handles = axes[0].get_legend().legendHandles
    axes[0].legend(handles=handles[2:],labels=list(added_plots.keys()))
    axes[0].set_title(names['sub_tile'], fontsize=10, style='italic',  loc='left')
    

#     axes[0].set_ylabel(names['y_tiles'][0])
#     axes[2].set_ylabel(names['y_tiles'][1])
    return fig, axes
   
df.columns
Index(['Open', 'High', 'Low', 'Close', 'Volume', 'APZ_UPPER', 'APZ_LOWER',
       'MAMA', 'FAMA', 'MAMA_APZ_UPPER', 'MAMA_APZ_LOWER', 'FAMA_APZ_UPPER',
       'FAMA_APZ_LOWER'],
      dtype='object')

start = -100
end = df.shape[0]

names = {'main_title': f'{ticker}', 
         'sub_tile': 'APZ'}


aa_, bb_ = make_3panels2(df.iloc[start:end][['Open', 'High', 'Low', 'Close', 'Volume']], 
            df.iloc[start:end][['APZ_UPPER', 'MAMA','APZ_LOWER']],
             chart_type='hollow_and_filled',names = names)

png


start = -100
end = df.shape[0]

names = {'main_title': f'{ticker}', 
         'sub_tile': 'APZ'}

aa_, bb_ = make_3panels2(df.iloc[start:end][['Open', 'High', 'Low', 'Close', 'Volume']], 
            df.iloc[start:end][['MAMA_APZ_UPPER', 'MAMA','MAMA_APZ_LOWER']],
             chart_type='hollow_and_filled',names = names)

png


start = -100
end = df.shape[0]

names = {'main_title': f'{ticker}', 
         'sub_tile': 'APZ'}

aa_, bb_ = make_3panels2(df.iloc[start:end][['Open', 'High', 'Low', 'Close', 'Volume']], 
            df.iloc[start:end][['FAMA_APZ_UPPER', 'FAMA', 'FAMA_APZ_LOWER']],
             chart_type='hollow_and_filled',names = names)

png