Files
strategy-lab/research/strat_ORDER_IMBALANCE/v2_SINGLE.ipynb
2024-08-30 21:06:06 +02:00

46 KiB

ORDER Imbalance

  • introduced buyvolume and sellvolume on bar level.
  • calculated order imbalance ratio (buyvolume-sellvolume/totalvolume)
  • calculated on multiple timeframes
  • entry based on confluences imbalances

Note

The order imbalance does not necessarily cause a price change (i.e., there can be an order imbalance on the buy side, but the price does not have to go up, and vice versa). However, if there is a prolonged imbalance without a price change, it could indicate something.

Create a cumulative imbalance — accumulators that will build up when there are strong imbalances without a price change. This accumulator will charge up with the imbalance and discharge with the corresponding price change.

In [2]:
from dotenv import load_dotenv

#as V2realbot is client , load env variables here
env_file = "/Users/davidbrazda/Documents/Development/python/.env"
# Load the .env file
load_dotenv(env_file)

from v2realbot.utils.utils import zoneNY
import pandas as pd
import numpy as np
import vectorbtpro as vbt
# from itables import init_notebook_mode, show
import datetime
from itertools import product
from v2realbot.config import DATA_DIR
from lightweight_charts import JupyterChart, chart, Panel
from IPython.display import display

# init_notebook_mode(all_interactive=True)

vbt.settings.set_theme("dark")
vbt.settings['plotting']['layout']['width'] = 1280
vbt.settings.plotting.auto_rangebreaks = True
# Set the option to display with pagination
pd.set_option('display.notebook_repr_html', True)
pd.set_option('display.max_rows', 10)  # Number of rows per page
In [3]:
# Define the market open and close times
market_open = datetime.time(9, 30)
market_close = datetime.time(16, 0)
entry_window_opens = 1
entry_window_closes = 370
forced_exit_start = 380
forced_exit_end = 390

#LOAD FROM PARQUET
#list all files is dir directory with parquet extension
dir = DATA_DIR + "/notebooks/"
import os
files = [f for f in os.listdir(dir) if f.endswith(".parquet")]
print('\n'.join(map(str, files)))
file_name = "ohlcv_df-BAC-2023-01-01T09_30_00-2024-05-25T15_30_00-47BCFOPUVWZ-100.parquet"
ohlcv_df = pd.read_parquet(dir+file_name,engine='pyarrow')
#filter ohlcv_df to certain date range (assuming datetime index)
#ohlcv_df = ohlcv_df.loc["2024-02-12 9:30":"2024-02-14 16:00"]

#add vwap column to ohlcv_df
#ohlcv_df["hlcc4"] = (ohlcv_df["close"] + ohlcv_df["high"] + ohlcv_df["low"] + ohlcv_df["close"]) / 4

basic_data = vbt.Data.from_data(vbt.symbol_dict({"BAC": ohlcv_df}), tz_convert=zoneNY)
ohlcv_df= None
basic_data.wrapper.index.normalize().nunique()
trades_df-BAC-2024-01-01T09_30_00-2024-05-14T16_00_00-CO4B7VPWUZF-100.parquet
trades_df-BAC-2024-01-11T09:30:00-2024-01-12T16:00:00.parquet
trades_df-SPY-2024-01-01T09:30:00-2024-05-14T16:00:00.parquet
trades_df-BAC-2023-01-01T09_30_00-2024-05-25T16_00_00-47BCFOPUVWZ-100.parquet
ohlcv_df-BAC-2024-01-11T09:30:00-2024-01-12T16:00:00.parquet
trades_df-BAC-2024-05-15T09_30_00-2024-05-25T16_00_00-47BCFOPUVWZ-100.parquet
ohlcv_df-BAC-2024-01-01T09_30_00-2024-05-25T16_00_00-47BCFOPUVWZ-100.parquet
ohlcv_df-SPY-2024-01-01T09:30:00-2024-05-14T16:00:00.parquet
ohlcv_df-BAC-2024-01-01T09_30_00-2024-05-14T16_00_00-CO4B7VPWUZF-100.parquet
ohlcv_df-BAC-2023-01-01T09_30_00-2024-05-25T16_00_00-47BCFOPUVWZ-100.parquet
ohlcv_df-BAC-2023-01-01T09_30_00-2024-05-25T15_30_00-47BCFOPUVWZ-100.parquet
Out[3]:
351
In [ ]:
basic_data.data["BAC"].info()

Add resample function to custom columns

In [ ]:
from vectorbtpro.utils.config import merge_dicts, Config, HybridConfig
from vectorbtpro import _typing as tp
from vectorbtpro.generic import nb as generic_nb

_feature_config: tp.ClassVar[Config] = HybridConfig(
    {
        "buyvolume": dict(
            resample_func=lambda self, obj, resampler: obj.vbt.resample_apply(
                resampler,
                generic_nb.sum_reduce_nb,
            )
        ),
        "sellvolume": dict(
            resample_func=lambda self, obj, resampler: obj.vbt.resample_apply(
                resampler,
                generic_nb.sum_reduce_nb,
            )
        ),
        "trades": dict(
            resample_func=lambda self, obj, resampler: obj.vbt.resample_apply(
                resampler,
                generic_nb.sum_reduce_nb,
            )
        )
    }
)

basic_data._feature_config = _feature_config
In [ ]:
t1data = basic_data[['open', 'high', 'low', 'close', 'volume','vwap','buyvolume','trades','sellvolume']].resample("1T")
t1data = t1data.transform(lambda df: df.between_time('09:30', '16:00').dropna())
t1data.data["BAC"].info()

m30data  = basic_data[['open', 'high', 'low', 'close', 'volume','vwap','buyvolume','trades','sellvolume']].resample("30T")
m30data = m30data.transform(lambda df: df.between_time('09:30', '16:00').dropna())
m30data.data["BAC"].info()
In [ ]:
 
In [ ]:
bbands = vbt.talib("BBANDS").run(
        t1data.get("Close"))
In [ ]:
supertrend = vbt.SUPERTREND.run(t1data.high, t1data.low, t1data.close, period=14, multiplier=3)
direction_series = supertrend.direction
uptrend= pd.Series(False, index=direction_series.index)
downtrend= pd.Series(False, index=direction_series.index)

# -1 na 1
uptrend[1:] = (direction_series[1:] == 1) & (direction_series.shift(1)[1:] == -1)
# 1 na -1
downtrend[1:] = (direction_series[1:] == -1) & (direction_series.shift(1)[1:] == 1)
In [ ]:
supertrendm30 = vbt.SUPERTREND.run(m30data.high, m30data.low, m30data.close, period=14, multiplier=3)
direction_series = supertrendm30.direction
uptrend_m30= pd.Series(False, index=direction_series.index)
downtrend_m30= pd.Series(False, index=direction_series.index)
# -1 na 1
uptrend_m30[1:] = (direction_series[1:] == 1) & (direction_series.shift(1)[1:] == -1)
# 1 na -1
downtrend_m30[1:] = (direction_series[1:] == -1) & (direction_series.shift(1)[1:] == 1)
In [ ]:
macd = vbt.talib("MACD").run(m30data.close)
macd.macd
In [ ]:
pane1 = Panel(
    ohlcv=(t1data.data["BAC"],), #(series, entries, exits, other_markers)
    histogram=[], # [(series, name, "rgba(53, 94, 59, 0.6), opacity")]
    right=[#(bbands,), #[(series, name, entries, exits, other_markers)]
           (t1data.data["BAC"].vwap, "vwap", uptrend, downtrend),
           (supertrend.trend,"STtrend"),
           (supertrend.long,"STlong"),
           (supertrend.short,"STshort")
           ],
    left = [(supertrend.direction,"STdirection")],
    # right=[(bbands.upperband, "upperband",),
    #       (bbands.lowerband, "lowerband",),
    #       (bbands.middleband, "middleband",)
    #       ], #[(series, name, entries, exits, other_markers)]
    middle1=[],
    middle2=[],
)

pane2 = Panel(
    ohlcv=(m30data.data["BAC"],uptrend_m30, downtrend_m30), #(series, entries, exits, other_markers)
    histogram=[], # [(series, name, "rgba(53, 94, 59, 0.6), opacity")]
    right=[#(bbands,), #[(series, name, entries, exits, other_markers)]
           (supertrendm30.trend,"STtrend30"),
           (supertrendm30.long,"STlong30"),
           (supertrendm30.short,"STshort30")
           ],
    left = [(supertrendm30.direction,"STdirection30")],
    # right=[(bbands.upperband, "upperband",),
    #       (bbands.lowerband, "lowerband",),
    #       (bbands.middleband, "middleband",)
    #       ], #[(series, name, entries, exits, other_markers)]
    middle1=[],
    middle2=[],
    title = "30m")

pane3 = Panel(
    ohlcv=(m30data.data["BAC"],), #(series, entries, exits, other_markers)
    histogram=[(macd.macdhist,"macdhist30",None,0.5)], # [(series, name, "rgba(53, 94, 59, 0.6), opacity")]
    # right=[#(bbands,), #[(series, name, entries, exits, other_markers)]
    #        (supertrendm30.trend,"STtrend30"),
    #        (supertrendm30.long,"STlong30"),
    #        (supertrendm30.short,"STshort30")
    #        ],
    left = [(macd.macd,"macd30"),
            (macd.macdsignal,"macdsignal30")
            ],
    # right=[(bbands.upperband, "upperband",),
    #       (bbands.lowerband, "lowerband",),
    #       (bbands.middleband, "middleband",)
    #       ], #[(series, name, entries, exits, other_markers)]
    middle1=[],
    middle2=[],
    title = "30m_macd")

ch = chart([pane1, pane2, pane3], sync=False, size="l", xloc=slice("2024-02-12 09:30","2024-03-12"))
In [ ]:
buyvolume = t1data.data["BAC"].buyvolume
sellvolume = t1data.data["BAC"].sellvolume
totalvolume = buyvolume + sellvolume

#adjust to minimal value to avoid division by zero
sellvolume_adjusted = sellvolume.replace(0, 1e-10)
oibratio = buyvolume / sellvolume

#cumulative order flow (net difference)
cof = buyvolume - sellvolume

# Calculate the order imbalance (net differene) normalize the order imbalance by calculating the difference between buy and sell volumes and then scaling it by the total volume.
order_imbalance = cof / totalvolume
order_imbalance = order_imbalance.fillna(0) #nan nahradime 0

order_imbalance_allvolume = cof / t1data.data["BAC"].volume

order_imbalance_sma = vbt.indicator("talib:EMA").run(order_imbalance, timeperiod=5)
short_signals = order_imbalance.vbt < -0.5
#short_entries = oibratio.vbt < 0.01
short_signals.value_counts()
short_signals.name = "short_entries"
#.fillna(False)
short_exits = short_signals.shift(-2).fillna(False).astype(bool)
In [ ]:
pane1 = Panel(
    ohlcv=(t1data.data["BAC"],), #(series, entries, exits, other_markers)
    histogram=[(order_imbalance_allvolume, "oib_allvolume", "rgba(53, 94, 59, 0.6)",0.5),
               (t1data.data["BAC"].trades, "trades",None,0.4),
               ], # [(series, name, "rgba(53, 94, 59, 0.6)", opacity)]
    # right=[
    #        (supertrend.trend,"STtrend"),
    #        (supertrend.long,"STlong"),
    #        (supertrend.short,"STshort")
    #        ],
    # left = [(supertrend.direction,"STdirection")],
    # right=[(bbands.upperband, "upperband",),
    #       (bbands.lowerband, "lowerband",),
    #       (bbands.middleband, "middleband",)
    #       ], #[(series, name, entries, exits, other_markers)]
    middle1=[],
    middle2=[],
)

pane2 = Panel(
    ohlcv=(basic_data.data["BAC"],), #(series, entries, exits, other_markers)
    left=[(basic_data.data["BAC"].trades, "trades")],
    histogram=[(basic_data.data["BAC"].trades, "trades_hist", "white", 0.5)], #"rgba(53, 94, 59, 0.6)"
    #           ], # [(series, name, "rgba(53, 94, 59, 0.6)")]
    # right=[
    #        (supertrend.trend,"STtrend"),
    #        (supertrend.long,"STlong"),
    #        (supertrend.short,"STshort")
    #        ],
    # left = [(supertrend.direction,"STdirection")],
    # right=[(bbands.upperband, "upperband",),
    #       (bbands.lowerband, "lowerband",),
    #       (bbands.middleband, "middleband",)
    #       ], #[(series, name, entries, exits, other_markers)]
    middle1=[],
    middle2=[],
)


ch = chart([pane1, pane2], size="m")
In [ ]:
##z tohoto si udelat plot funkci (i pro entries,exits)
#t1data = t1data[["open", "high", "low", "close", "volume"]]
chart = JupyterChart(width=1000, height=600, inner_width=1, inner_height=0.5, leftScale=True)
#set resolution
t1data = basic_data[['open', 'high', 'low', 'close', 'volume','vwap','buyvolume','sellvolume']].resample("1T")
t1data = t1data.transform(lambda df: df.between_time('09:30', '16:00').dropna())
chart.set(t1data.data["BAC"])
line_vwap = chart.create_line(name="vwap")#, color="blue")
line_vwap.set(t1data.vwap)


chart.topbar.textbox("title","Nadpis")
chart2 = chart.create_subchart(position='right', width=1, height=0.5, sync=True, leftScale=True)
t2data = basic_data[['open', 'high', 'low', 'close', 'volume','vwap','buyvolume','sellvolume']].resample("5T")
t2data = t2data.transform(lambda df: df.between_time('09:30', '16:00').dropna())


#5min close realigned to 1T
close_realigned = t2data.close.vbt.realign_closing("1T").between_time('09:30', '16:00').dropna()
close_realigned = close_realigned[close_realigned.index.dayofweek < 5]
#close_realigned = close_realigned[close_realigned.index.dayofweek < 5]
line1 = chart.create_line(name="5minclose")#, color="green")
line1.set(close_realigned)

#sma z realigned dat
sma_tp = 20
sma_t2 = vbt.indicator("talib:EMA").run(close_realigned, timeperiod=sma_tp)
smaline = chart.create_line(name=f"sma{sma_tp}")#, color="blue")
smaline.set(sma_t2)


#sma z puvodnich resamplovanych dat plus navic realign, melo by byt stejne 
sma_real = vbt.indicator("talib:EMA").run(t2data.close, timeperiod=sma_tp)
sma_real_value = sma_real.real.vbt.realign_closing("1T").between_time('09:30', '16:00').dropna()
sma_real_value = sma_real_value[sma_real_value.index.dayofweek < 5]
smaline_real = chart.create_line(name=f"smareal{sma_tp}", color="yellow")
smaline_real.set(sma_real_value)

#resample 15T
t15data = basic_data[['open', 'high', 'low', 'close', 'volume','vwap','buyvolume','sellvolume']].resample("15T")
t15data = t15data.transform(lambda df: df.between_time('09:30', '16:00').dropna())

#5min close realigned to 1T
close_15realigned = t15data.close.vbt.realign_closing("1T").between_time('09:30', '16:00').dropna()
close_15realigned = close_15realigned[close_15realigned.index.dayofweek < 5]
#close_realigned = close_realigned[close_realigned.index.dayofweek < 5]
line2 = chart.create_line(name="15minclose")#, color="pink")
line2.set(close_15realigned)


chart.legend(True)
hst = chart2.create_histogram(name="buyvolume", color="rgba(53, 94, 59, 0.6)") #green transparent
hst1 = chart2.create_histogram(name="sellvolume", color="rgba(165, 42, 42, 0.6)") #red transparent
hst.set(t1data.data["BAC"])
hst1.set(t1data.data["BAC"])
line2 = chart2.create_line(name="5minclose")#, color="green")
line2.set(close_realigned)

lineoib = chart2.create_line(name="oib", priceScaleId="left") #color="violet", 
#lineoib.scale(0.7,0)
lineoib.set(order_imbalance_allvolume)

lineoib_sma = chart2.create_line(name="oibsma5", priceScaleId="left") #, color="blue", 
lineoib_sma.set(order_imbalance_sma)

chart.fit()
chart2.legend(True)
#
line2.markers_set(short_signals, "entries")
# TODO jelikoz se davaji do jednoho pole je treba zajistit spravne sortovani
# domyslet jak to pojmout iterativni doplnovani markeru
line2.markers_set(short_exits, "exits")


chart2.fit()
chart.load()
In [ ]:
 
In [ ]:
short_signals.info()
In [ ]:
#vbt.IF.list_indicators("*ma")
vbt.phelp(vbt.indicator("talib:EMA").run)
In [ ]:
sma = vbt.indicator("talib:EMA").run(t1data.close, timeperiod=20)
sma.real.info()
In [ ]:
rr = vbt.RSI.run(t1data.close)
type(rr)
In [ ]:
buyvolume = t1data.data["BAC"].buyvolume
sellvolume = t1data.data["BAC"].sellvolume
totalvolume = buyvolume + sellvolume

#adjust to minimal value to avoid division by zero
sellvolume_adjusted = sellvolume.replace(0, 1e-10)
oibratio = buyvolume / sellvolume

#cumulative order flow (net difference)
cof = buyvolume - sellvolume

# Calculate the order imbalance (net differene) normalize the order imbalance by calculating the difference between buy and sell volumes and then scaling it by the total volume.
order_imbalance = cof / totalvolume
order_imbalance = order_imbalance.fillna(0) #nan nahradime 0

order_imbalance_allvolume = cof / t1data.data["BAC"].volume
In [ ]:
order_imbalance_sma = vbt.indicator("talib:EMA").run(order_imbalance, timeperiod=5)
short_signals = order_imbalance.vbt < -0.5
#short_entries = oibratio.vbt < 0.01
short_signals.value_counts()
short_signals.name = "short_entries"
In [ ]:
short_signals.info()
In [ ]:
short_signals
In [ ]:
order_imbalance.fillna(0)
In [ ]:
 
In [ ]:
order_imbalance.vbt.plot()
In [ ]:
order_imbalance
In [ ]:
chartN = JupyterChart(width=500, height=300, inner_width=1, inner_height=0.3, leftScale=True)
t1data = basic_data[['open', 'high', 'low', 'close', 'volume','vwap','buyvolume','sellvolume']].resample("1T")
t1data = t1data.transform(lambda df: df.between_time('09:30', '16:00').dropna())
chartN.set(t1data.data["BAC"])
line_sma = chartN.create_line(name="sma", priceScaleId="right")#, color="blue")
line_sma.set(sma)
# line_sma.markers_set(short_signals, "entries")
# line_sma.markers_set(short_exits, "exits")
# hst = chartN.create_histogram(name="oivol")
# hst.set(order_imbalance_allvolume)
# chartN.legend(True)
# chartN.fit()

# subchart = chartN.create_subchart(position='right', width=1, height=0.5, sync=False, leftScale=True)
# # subchart.set(t1data.data["BAC"])
# line_sma1 = subchart.create_line(name="smao", priceScaleId="left")#, color="blue")
# line_sma1.set(sma)
# # line_sma1.markers_set(short_signals, "entries")
# # line_sma1.markers_set(short_exits, "exits")
# hsto = subchart.create_histogram(name="oivolo")
# hsto.set(order_imbalance_sma)

chart2 = chartN.create_subchart(position='left', width=1, height=0.5, sync=True, leftScale=True, toolbox=True)
# hst = chart2.create_histogram(name="buyvolume", color="rgba(53, 94, 59, 0.6)") #green transparent
# hst1 = chart2.create_histogram(name="sellvolume", color="rgba(165, 42, 42, 0.6)") #red transparent
# hst.set(t1data.data["BAC"])
# hst1.set(t1data.data["BAC"])
line2 = chart2.create_line(name="sma")#, color="green")
line2.set(sma)
chart2.topbar.textbox("title","Nadpis")
# chartN.topbar.textbox("title","NadpisT")

# subchart.legend(True)
# subchart.fit()
chartN.load()
In [ ]:
##z tohoto si udelat plot funkci (i pro entries,exits)
#t1data = t1data[["open", "high", "low", "close", "volume"]]
chart = JupyterChart(width=1000, height=600, inner_width=1, inner_height=0.5, leftScale=True)
#set resolution
t1data = basic_data[['open', 'high', 'low', 'close', 'volume','vwap','buyvolume','sellvolume']].resample("1T")
t1data = t1data.transform(lambda df: df.between_time('09:30', '16:00').dropna())
chart.set(t1data.data["BAC"])
line_vwap = chart.create_line(name="vwap")#, color="blue")
line_vwap.set(t1data.vwap)


chart.topbar.textbox("title","Nadpis")
chart2 = chart.create_subchart(position='right', width=1, height=0.5, sync=True, leftScale=True)
t2data = basic_data[['open', 'high', 'low', 'close', 'volume','vwap','buyvolume','sellvolume']].resample("5T")
t2data = t2data.transform(lambda df: df.between_time('09:30', '16:00').dropna())


#5min close realigned to 1T
close_realigned = t2data.close.vbt.realign_closing("1T").between_time('09:30', '16:00').dropna()
close_realigned = close_realigned[close_realigned.index.dayofweek < 5]
#close_realigned = close_realigned[close_realigned.index.dayofweek < 5]
line1 = chart.create_line(name="5minclose")#, color="green")
line1.set(close_realigned)

#sma z realigned dat
sma_tp = 20
sma_t2 = vbt.indicator("talib:EMA").run(close_realigned, timeperiod=sma_tp)
smaline = chart.create_line(name=f"sma{sma_tp}")#, color="blue")
smaline.set(sma_t2)


#sma z puvodnich resamplovanych dat plus navic realign, melo by byt stejne 
sma_real = vbt.indicator("talib:EMA").run(t2data.close, timeperiod=sma_tp)
sma_real_value = sma_real.real.vbt.realign_closing("1T").between_time('09:30', '16:00').dropna()
sma_real_value = sma_real_value[sma_real_value.index.dayofweek < 5]
smaline_real = chart.create_line(name=f"smareal{sma_tp}", color="yellow")
smaline_real.set(sma_real_value)

#resample 15T
t15data = basic_data[['open', 'high', 'low', 'close', 'volume','vwap','buyvolume','sellvolume']].resample("15T")
t15data = t15data.transform(lambda df: df.between_time('09:30', '16:00').dropna())

#5min close realigned to 1T
close_15realigned = t15data.close.vbt.realign_closing("1T").between_time('09:30', '16:00').dropna()
close_15realigned = close_15realigned[close_15realigned.index.dayofweek < 5]
#close_realigned = close_realigned[close_realigned.index.dayofweek < 5]
line2 = chart.create_line(name="15minclose")#, color="pink")
line2.set(close_15realigned)


chart.legend(True)
hst = chart2.create_histogram(name="buyvolume", color="rgba(53, 94, 59, 0.6)") #green transparent
hst1 = chart2.create_histogram(name="sellvolume", color="rgba(165, 42, 42, 0.6)") #red transparent
hst.set(t1data.data["BAC"])
hst1.set(t1data.data["BAC"])
line2 = chart2.create_line(name="5minclose")#, color="green")
line2.set(close_realigned)

lineoib = chart2.create_line(name="oib", priceScaleId="left") #color="violet", 
#lineoib.scale(0.7,0)
lineoib.set(order_imbalance_allvolume)

lineoib_sma = chart2.create_line(name="oibsma5", priceScaleId="left") #, color="blue", 
lineoib_sma.set(order_imbalance_sma)

chart.fit()
chart2.legend(True)
#
line2.markers_set(short_signals, "entries")
# TODO jelikoz se davaji do jednoho pole je treba zajistit spravne sortovani
# domyslet jak to pojmout iterativni doplnovani markeru
line2.markers_set(short_exits, "exits")


chart2.fit()
chart.load()
In [ ]:
sma.info()
In [ ]:
#priminds list (same Y as price), secinds list (secondary Y napr. rsi), close, voluminds (volume based) list
def plot_2y_close(priminds, secinds, close, volumeinds, ohlcv=None):
    fig = vbt.make_subplots(rows=2, cols=1, shared_xaxes=True, 
                            specs=[[{"secondary_y": True}], [{"secondary_y": False}]], 
                            vertical_spacing=0.02, subplot_titles=("Price and Indicators", "Volume"))

    if ohlcv is not None:
        ohlcv.vbt.ohlcv.plot(fig=fig, add_trace_kwargs=dict(row=1, col=1))

    # Plotting the close price
    close.vbt.plot(fig=fig, add_trace_kwargs=dict(secondary_y=False,row=1, col=1), trace_kwargs=dict(line=dict(color="blue")))
    
    # Plotting primary indicators on the first row
    for ind in priminds:
        if isinstance(ind, pd.Series):
            #if series has no name, make the name same as the variable name
            
            ind = ind.vbt
        ind.plot(fig=fig, add_trace_kwargs=dict(secondary_y=False, row=1, col=1))
    
    # Plotting secondary indicators on the first row
    for ind in secinds:
        #ind = ind.rename(str(ind.name))
        if isinstance(ind, pd.Series):
            ind = ind.vbt
        ind.plot(fig=fig, add_trace_kwargs=dict(secondary_y=True, row=1, col=1), trace_kwargs=dict(line=dict(color="rgba(255, 0, 0, 0.4)")))
    
    for indvolume in volumeinds:
        # Plotting the volume on the second row
        indvolume.rename(str(indvolume.name)).vbt.barplot(fig=fig, add_trace_kwargs=dict(secondary_y=False, row=2, col=1))
        #vbt.Bar(indvolume, fig=fig, add_trace_kwargs=dict(secondary_y=False, row=2, col=1))
    
    return fig

fig = plot_2y_close([sma], [order_imbalance.rename("order_imbalance_norm"),order_imbalance_sma.real.rename("oib_sma")], t1data.close, [t1data.data["BAC"].buyvolume, t1data.data["BAC"].sellvolume, t1data.volume], t1data.data["BAC"])
fig.update_yaxes(range=[33,34], secondary_y=False, row=1, col=1) #update y axis range
fig.update_yaxes(range=[-1,1], secondary_y=True, row=1, col=1)
In [ ]:
%matplotlib inline
t0data = basic_data
t1data = basic_data[['open', 'high', 'low', 'close', 'volume','vwap']].resample("1T")
t2data = basic_data[['open', 'high', 'low', 'close', 'volume','vwap']].resample("15T")
t3data = basic_data[['open', 'high', 'low', 'close', 'volume','vwap']].resample("30T")
t4data = basic_data[['open', 'high', 'low', 'close', 'volume', 'vwap']].resample("D").dropna()

t1data = t1data.transform(lambda df: df.between_time('09:30', '16:00').dropna())
t2data = t2data.transform(lambda df: df.between_time('09:30', '16:00').dropna())
t3data = t3data.transform(lambda df: df.between_time('09:30', '16:00').dropna())

#30min data to daily
# t4data = t3data.resample("D").dropna()

#t4data = t4data.transform(lambda df: df.between_time('09:30', '16:00').dropna())
#m1data.data["SPY"].info()

#m1data.data["SPY"].vbt.ohlcv.plot()
#h2data.data["SPY"].vbt.ohlcv.plot()
#ddata.data["SPY"]
t2data.data["BAC"].vbt.ohlcv.plot().show()


#t4data.data["BAC"]
In [ ]:
t2data.close

#in df remove rows with nan
In [ ]:
#realign na 1T = t1data + oriznout main session
t2data_vwap = t2data.vwap.vbt.realign_closing("1T").between_time('09:30', '16:00').dropna()
t3data_vwap = t3data.vwap.vbt.realign_closing("1T").between_time('09:30', '16:00').dropna()
t4data_vwap = t4data.vwap.vbt.realign_closing("1T").dropna()
In [ ]:
t2data_vwap
In [ ]:
def plot_2y_close(priminds, secinds, close):
    fig = vbt.make_subplots(rows=1, cols=1, shared_xaxes=True, specs=[[{"secondary_y": True}]], vertical_spacing=0.02, subplot_titles=("MOM", "Price" ))
    close.vbt.plot(fig=fig, add_trace_kwargs=dict(secondary_y=False), trace_kwargs=dict(line=dict(color="blue")))
    for ind in priminds:
        if isinstance(ind, pd.Series):
            ind = ind.vbt
        ind.plot(fig=fig, add_trace_kwargs=dict(secondary_y=False))
    for ind in secinds:
        if isinstance(ind, pd.Series):
            ind = ind.vbt
        ind.plot(fig=fig, add_trace_kwargs=dict(secondary_y=True))
    return fig
In [ ]:
t4data.clos.vbt 
In [ ]:
obvind = vbt.indicator.obv.run(t1data.close, t1data.volume)
In [ ]:
t1_lengtgh = 15
t2_length = 15
t3_length = 15
t4_length = 5
t1_th = 0.1
t2_th = 0.1
t3_th = 0.1
t4_th = 0.1



#minute
t1slope = vbt.indicator("talib:LINEARREG_SLOPE ").run(t1data.close, timeperiod=t1_lengtgh) # -0.09, 0.09
t2slope = vbt.indicator("talib:LINEARREG_SLOPE ").run(t2data.vwap, timeperiod=t2_length) #   -0.08 , 0.079
t3slope = vbt.indicator("talib:LINEARREG_SLOPE ").run(t3data.vwap, timeperiod=t3_length) #   -0.08, 0.08
#daily
t4slope = vbt.indicator("talib:LINEARREG_SLOPE ").run(t4data.vwap, timeperiod=t4_length) #   -0.1, 0.09

plot_2y_close(priminds=[], secinds=[t1slope, t2slope, t3slope, t4slope], close=t1data.close).show()
In [ ]:
#thirtymin_slope = thirtymin_slope.real.rename("30min") #timto se prejmenuje real na 30min
t3slope = t3slope.real.vbt.realign_closing("1T").between_time('09:30', '16:00').dropna()
##filter daily_slope_to_compare to only monday to friday
t3slope = t3slope[t3slope.index.dayofweek < 5]

#t3slope.info()

t2slope = t2slope.real.vbt.realign_closing("1T").between_time('09:30', '16:00').dropna()
##filter daily_slope_to_compare to only monday to friday
t2slope = t2slope[t2slope.index.dayofweek < 5]

t2slope.info()
In [ ]:
oibratio
In [ ]:
#
short_signals = order_imbalance.vbt < -0.3
#short_entries = oibratio.vbt < 0.01
short_signals.value_counts()

long_signals = order_imbalance.vbt > 0.3
#entries = oibratio.vbt > 10
long_signals.value_counts()
In [ ]:
fig = vbt.make_subplots(rows=3, cols=1, shared_xaxes=True, 
                        specs=[[{"secondary_y": True}], [{"secondary_y": True}], [{"secondary_y": False}]], 
                        vertical_spacing=0.02, subplot_titles=("Price and Indicators", "Volume"))
t1data.data["BAC"].vbt.ohlcv.plot(fig=fig, add_trace_kwargs=dict(secondary_y=False, row=1, col=1))
#oibratio.vbt.plot(fig=fig, add_trace_kwargs=dict(secondary_y=True, row=1, col=1))
order_imbalance.vbt.plot(fig=fig, add_trace_kwargs=dict(secondary_y=True, row=1, col=1))
long_signals.vbt.signals.plot_as_entries(t1data.close, fig=fig, trace_kwargs=dict(name="LONGS",
                                                                                    line=dict(color="#ffe476"),
                                                                                    marker=dict(color="limegreen"),
                                                                                    fill=None,
                                                                                    connectgaps=True,
                                                                                    ), add_trace_kwargs=dict(secondary_y=False, row=1, col=1))

short_signals.vbt.signals.plot_as_entries(t1data.close, fig=fig, trace_kwargs=dict(name="SHORTS",
                                                                                    line=dict(color="#ffe476"),
                                                                                    marker=dict(color="red"),
                                                                                    fill=None,
                                                                                    connectgaps=True,
                                                                                    ), add_trace_kwargs=dict(secondary_y=False, row=1, col=1))
In [ ]:
# thirtymin_slope_to_compare.vbt.xloc["04-16-2024"].get()
thirty_down_signal.vbt.xloc["04-16-2024"].get()
In [ ]:
#short_signal = t1slope.real_below(t1_th) & t2slope.real_below(t2_th) & t3slope.real_below(t3_th) & t4slope.real_below(t4_th)
#long_signal = t1slope.real_above(t1_th) & t2slope.real_above(t2_th) & t3slope.real_above(t3_th) & t4slope.real_above(t4_th)

#test na daily s reversem  crossed 0
short_signal = t2slope.vbt < -0.01 & t3slope.vbt < -0.01  #min value of threshold
long_signal = t2slope.vbt > 0.01 & t3slope.vbt > 0.01  #min

# thirty_up_signal = t3slope.vbt.crossed_above(0.01)
# thirty_down_signal = t3slope.vbt.crossed_below(-0.01)

fig = plot_2y_close(priminds=[], secinds=[t3slope], close=t1data.close)
#short_signal.vbt.signals.plot_as_entries(basic_data.close, fig=fig)

short_signal.vbt.signals.plot_as_entries(t1data.close, fig=fig, trace_kwargs=dict(name="SHORTS",
                                                                                    line=dict(color="#ffe476"),
                                                                                    marker=dict(color="red", symbol="triangle-down"),
                                                                                    fill=None,
                                                                                    connectgaps=True,
                                                                                    ))
long_signal.vbt.signals.plot_as_entries(t1data.close, fig=fig, trace_kwargs=dict(name="LONGS",
                                                                                    line=dict(color="#ffe476"),
                                                                                    marker=dict(color="limegreen"),
                                                                                    fill=None,
                                                                                    connectgaps=True,
                                                                                    ))

# thirty_down_signal.vbt.signals.plot_as_entries(t1data.close, fig=fig, trace_kwargs=dict(name="DOWN30",
#                                                                                     line=dict(color="#ffe476"),
#                                                                                     marker=dict(color="yellow", symbol="triangle-down"),
#                                                                                     fill=None,
#                                                                                     connectgaps=True,
#                                                                                     ))
# thirty_up_signal.vbt.signals.plot_as_entries(t1data.close, fig=fig, trace_kwargs=dict(name="UP30",
#                                                                                     line=dict(color="#ffe476"),
#                                                                                     marker=dict(color="grey"),
#                                                                                     fill=None,
#                                                                                     connectgaps=True,
#                                                                                     ))

# thirtymin_slope_to_compare.vbt.plot(fig=fig, add_trace_kwargs=dict(secondary_y=True), trace_kwargs=dict(name="30min slope",
#                                                                                         line=dict(color="yellow"),                                                                                     
#                                                                                         fill=None,
#                                                                                         connectgaps=True,
#                                                                                         ))

fig.show()
# print("short signal")
# print(short_signal.value_counts())

#forced_exit = pd.Series(False, index=close.index)
forced_exit = basic_data.symbol_wrapper.fill(False)
#entry_window_open = pd.Series(False, index=close.index)
entry_window_open=  basic_data.symbol_wrapper.fill(False)

# Calculate the time difference in minutes from market open for each timestamp
elapsed_min_from_open = (forced_exit.index.hour - market_open.hour) * 60 + (forced_exit.index.minute - market_open.minute)

entry_window_open[(elapsed_min_from_open >= entry_window_opens) & (elapsed_min_from_open < entry_window_closes)] = True

#print(entry_window_open.value_counts())

forced_exit[(elapsed_min_from_open >= forced_exit_start) & (elapsed_min_from_open < forced_exit_end)] = True
short_entries = (short_signal & entry_window_open)
short_exits = forced_exit

entries = (long_signal & entry_window_open)
exits = forced_exit
#long_entries.info()
#number of trues and falses in long_entries
# print(short_exits.value_counts())
# print(short_entries.value_counts())

#fig = plot_2y_close([],[momshort, rocp], close)
#short_signal.vbt.signals.plot_as_entries(close, fig=fig, add_trace_kwargs=dict(secondary_y=False))
#print(sl_stop)
#short_entries=short_entries, short_exits=short_exits,
# pf = vbt.Portfolio.from_signals(close=basic_data, entries=short_entries, exits=exits, tsl_stop=0.005, tp_stop = 0.05, fees=0.0167/100, freq="1s") #sl_stop=sl_stop, tp_stop = sl_stop,

# pf.stats()
In [ ]:
forced_exit = t1data.symbol_wrapper.fill(False)
#entry_window_open = pd.Series(False, index=close.index)
entry_window_open=  t1data.symbol_wrapper.fill(False)

# Calculate the time difference in minutes from market open for each timestamp
elapsed_min_from_open = (forced_exit.index.hour - market_open.hour) * 60 + (forced_exit.index.minute - market_open.minute)

entry_window_open[(elapsed_min_from_open >= entry_window_opens) & (elapsed_min_from_open < entry_window_closes)] = True

#print(entry_window_open.value_counts())

forced_exit[(elapsed_min_from_open >= forced_exit_start) & (elapsed_min_from_open < forced_exit_end)] = True
short_entries = (short_signals & entry_window_open)
short_exits = forced_exit

entries = (long_signals & entry_window_open)
exits = forced_exit

pf = vbt.Portfolio.from_signals(close=t1data, entries=entries, exits=exits, short_entries=short_entries, short_exits=exits,
td_stop=2, time_delta_format="rows",
tsl_stop=0.005, tp_stop = 0.005, fees=0.0167/100)#, freq="1s") #sl_stop=sl_stop, tp_stop = sl_stop,

pf.stats()
In [ ]:
pf.plot()
In [ ]:
pf.get_drawdowns().records_readable
In [ ]:
pf.orders.records_readable