BRAR

References

Definition

Emotional index (BRAR) is also called popularity intention index. It consists of two indicators: popularity index (AR) and willingness index (BR). Both the AR indicator and the BR indicator are technical indicators based on the analysis of historical stock prices.

  • the BRAR indicator is 100-centric. When BR around 100 indicates the sentiment of the market is in a very balanced state.
  • when the BRAR starts to fluctuate, it can rise above 200 or drop below 80.

Read the indicator

  • AR indicator can be used alone, and BR indicator needs to be used in conjunction with AR indicators in order to be effective.
  • BRAR is not suitable for capturing a large bottom, but it can be used to capture a local bottom.

Buy signals:

  • BR line normally runs above AR line, when BR crosses AR and runs below AR line
  • BR<40 and AR<60
  • BR <AR and AR <50
  • BR <AR and BR <100

Sell signals

  • BR>400 and AR>180
  • BR rapadily increases but AR stays flat or slightly drops
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', 'GKOS']
#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 21:31:52.358741 ^GSPC (5710, 7) 1999-12-31 00:00:00 2022-09-09 00:00:00
2022-09-10 21:31:52.676873 GSK (5710, 7) 1999-12-31 00:00:00 2022-09-09 00:00:00
2022-09-10 21:31:53.016940 NVO (5710, 7) 1999-12-31 00:00:00 2022-09-09 00:00:00
2022-09-10 21:31:53.171193 GKOS (1816, 7) 2015-06-25 00:00:00 2022-09-09 00:00:00
ticker = 'GKOS'
dfs[ticker].tail(5)
Open High Low Close Volume Dividends Stock Splits
Date
2022-09-02 49.590000 50.900002 48.419998 48.830002 650900 0 0
2022-09-06 49.200001 49.200001 47.630001 48.099998 334400 0 0
2022-09-07 52.759998 60.919998 51.490002 57.009998 4560500 0 0
2022-09-08 56.439999 59.599998 56.439999 58.380001 1106900 0 0
2022-09-09 58.369999 58.529999 55.860001 56.299999 1291100 0 0
Define BRAR calculation function
def BRAR(OPEN,CLOSE,HIGH,LOW,M1=26):                 #BRAR-ARBR 情绪指标  
    AR = SUM(HIGH - OPEN, M1) / SUM(OPEN - LOW, M1) * 100
    BR = SUM(MAX(0, HIGH - REF(CLOSE, 1)), M1) / SUM(MAX(0, REF(CLOSE, 1) - LOW), M1) * 100
    return AR, BR        
def cal_brar(ohlc: pd.DataFrame, period: int = 26) -> pd.DataFrame:
    """
    BUY: AR<60 BR<40
    SELL: BR>400, AR>180
    
    reference:
    
    https://github.com/mpquant/MyTT/blob/ea4f14857ecc46a3739a75ce2e6974b9057a6102/MyTT.py
    https://github.com/twopirllc/pandas-ta/blob/2a24fdc1b69110332db39eda9723a628f75eaf7a/pandas_ta/momentum/brar.py
    
    """
    
    ohlc = ohlc.copy()
    ohlc.columns = [c.lower() for c in ohlc.columns]    
    
    h, l, o, c = ohlc["high"], ohlc["low"], ohlc["open"], ohlc["close"]
    c1 = c.shift(1)
    
    a0 = (h-o).rolling(period).sum()
    a1 = (o-l).rolling(period).sum()
    ar = a0/a1*100
    
    b0 = (h - c1).apply(lambda x: max(0, x)).rolling(period).sum()
    b1 = (c1 - l).apply(lambda x: max(0, x)).rolling(period).sum()
    br = b0/b1*100
    
    return pd.DataFrame(data={'AR': ar.values, 'BR': br.values}, index=ohlc.index)
Calculate BRAR
df = dfs[ticker][['Open', 'High', 'Low', 'Close', 'Volume']]
df = df.round(2)
help(cal_brar)
Help on function cal_brar in module __main__:

cal_brar(ohlc: pandas.core.frame.DataFrame, period: int = 26) -> pandas.core.frame.DataFrame
    BUY: AR<60 BR<40
    SELL: BR>400, AR>180
    
    reference:
    
    https://github.com/mpquant/MyTT/blob/ea4f14857ecc46a3739a75ce2e6974b9057a6102/MyTT.py
    https://github.com/twopirllc/pandas-ta/blob/2a24fdc1b69110332db39eda9723a628f75eaf7a/pandas_ta/momentum/brar.py
df_ta = cal_brar(df, period = 14)
df = df.merge(df_ta, left_index = True, right_index = True, how='inner' )

del df_ta
gc.collect()
122
#     BUY: AR<60 BR<40
#     SELL: BR>400, AR>180

df['B'] = ((df["AR"]<60) & (df["BR"]<40)).astype(int)*(df['High']+df['Low'])/2
df['S'] = ((df["AR"]>180) & (df["BR"]>400)).astype(int)*(df['High']+df['Low'])/2
display(df.head(5))
display(df.tail(5))
Open High Low Close Volume AR BR B S
Date
2015-06-25 29.11 31.95 28.00 31.22 7554700 NaN NaN 0.0 0.0
2015-06-26 30.39 30.39 27.51 28.00 1116500 NaN NaN 0.0 0.0
2015-06-29 27.70 28.48 27.51 28.00 386900 NaN NaN 0.0 0.0
2015-06-30 27.39 29.89 27.39 28.98 223900 NaN NaN 0.0 0.0
2015-07-01 28.83 29.00 27.87 28.00 150000 NaN NaN 0.0 0.0
Open High Low Close Volume AR BR B S
Date
2022-09-02 49.59 50.90 48.42 48.83 650900 48.783455 57.727550 0.0 0.0
2022-09-06 49.20 49.20 47.63 48.10 334400 45.229469 59.610553 0.0 0.0
2022-09-07 52.76 60.92 51.49 57.01 4560500 96.770186 161.901306 0.0 0.0
2022-09-08 56.44 59.60 56.44 58.38 1106900 116.763754 187.993921 0.0 0.0
2022-09-09 58.37 58.53 55.86 56.30 1291100 110.436893 180.231716 0.0 0.0
df[['AR','BR']].hist(bins=50)
array([[<AxesSubplot:title={'center':'AR'}>,
        <AxesSubplot:title={'center':'BR'}>]], 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",


#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 plot_3panels(main_data, add_data=None, mid_panel=None, chart_type='candle', names=None, 
                  figratio=(14,9)):


    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=False,
                  panel_ratios=(4,2), tight_layout=True, style=style, returnfig=True)
    
    if names is None:
        names = {'main_title': '', 'sub_tile': ''}
    


    added_plots = { 
        'S':  mpf.make_addplot(add_data['S'], panel=0, color='blue', type='scatter', marker=r'${S}$' , markersize=100, secondary_y=False),   
        'B':  mpf.make_addplot(add_data['B'], panel=0, color='blue', type='scatter', marker=r'${B}$' , markersize=100, secondary_y=False), 
        
        'AR': mpf.make_addplot(mid_panel['AR'], panel=1, color='dodgerblue', secondary_y=False), 
        'BR': mpf.make_addplot(mid_panel['BR'], panel=1, color='tomato', secondary_y=False), 
#         'AO-SIGNAL': mpf.make_addplot(mid_panel['AO']-mid_panel['SIGNAL'], type='bar',width=0.7,panel=1, color="pink",alpha=0.65,secondary_y=False),
    }

                         

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

    axes[0].set_title(names['sub_tile'], fontsize=10, style='italic',  loc='left')
    
    

    
    #set legend

    axes[2].legend([None]*2)
    handles = axes[2].get_legend().legendHandles
#     print(handles)
    axes[2].legend(handles=handles,labels=['AR', 'BR'])
    #axes[2].set_title('AO', fontsize=10, style='italic',  loc='left')
    axes[2].set_ylabel('BRAR')
    
    

#     axes[0].set_ylabel(names['y_tiles'][0])
    return fig, axes
   

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

names = {'main_title': f'{ticker}', 
         'sub_tile': 'BRAR: BUY: AR<60 BR<40; SELL: BR>400, AR>180'}


aa_, bb_ = plot_3panels(df.iloc[start:end][['Open', 'High', 'Low', 'Close', 'Volume']], 
             df.iloc[start:end][['B', 'S']],
             df.iloc[start:end][['AR', 'BR']], 
             chart_type='hollow_and_filled',
                     names = names, 
                    )

png