Context is not updated in initialize procedure of zipline strategy

Hi,
I came across strange behaviour of context variable in Zipline live algo. Initialize routine is called every time you run algo in live mode (that's ok) but if you try to change context inside initialize routine it works only once. Next algo runs do not allow you to change context variable!
Example algo:

import logging
from quantrocket.flightlog import FlightlogHandler
log_level = logging.DEBUG
logger = logging.getLogger('test_zl')
logger.setLevel(log_level)
handler = FlightlogHandler(background=False)
logger.addHandler(handler)

def initialize(context):
    """
    Called once at the start of a backtest, and once per day at
    the start of live trading.
    """
    
    logger.debug(f'init start: df_init = {context.df_init if hasattr(context, "df_init") else "NA"}')
    logger.debug(f'init start: df_bts = {context.df_bts if hasattr(context, "df_bts") else "NA"}')
    logger.debug(f'init start: df_cross = {context.df_cross if hasattr(context, "df_cross") else "NA"}')

    if hasattr(context, 'df_init'):
        context.df_init.append(context.df_init[-1] + 1)
    else:
        context.df_init = [0]

    if hasattr(context, 'df_cross'):
        context.df_cross.append(context.df_cross[-1] + 1)
    else:
        context.df_cross = [0]
    
    logger.debug(f'init end: df_init = {context.df_init if hasattr(context, "df_init") else "NA"}')
    logger.debug(f'init end: df_bts = {context.df_bts if hasattr(context, "df_bts") else "NA"}')
    logger.debug(f'init end: df_cross = {context.df_cross if hasattr(context, "df_cross") else "NA"}')

def before_trading_start(context, data):
    """
    Called every day before market open.
    """
    logger.debug(f'bts start: df_init = {context.df_init if hasattr(context, "df_init") else "NA"}')
    logger.debug(f'bts start: df_bts = {context.df_bts if hasattr(context, "df_bts") else "NA"}')
    logger.debug(f'bts start: df_cross = {context.df_cross if hasattr(context, "df_cross") else "NA"}')
    
    if hasattr(context, 'df_bts'):
        context.df_bts.append(context.df_bts[-1] + 1)
    else:
        context.df_bts = [0]

    if hasattr(context, 'df_cross'):
        context.df_cross.append(context.df_cross[-1] + 1)
    else:
        context.df_cross = [0]
    
    logger.debug(f'bts end: df_init = {context.df_init if hasattr(context, "df_init") else "NA"}')
    logger.debug(f'bts end: df_bts = {context.df_bts if hasattr(context, "df_bts") else "NA"}')
    logger.debug(f'bts end: df_cross = {context.df_cross if hasattr(context, "df_cross") else "NA"}')

df_init is changed only in initialize
df_bts is changed only in before_trading_start
df_cross is changed in both initialize and before_trading_start

Strategy is run daily:

from quantrocket.zipline import trade
trade('STRATEGY_NAME', data_frequency='daily', account='YOUR ACCOUNT')

First run (everything's correct):
2021-10-11 13:08:43 test_zl: DEBUG init start: df_init = NA
2021-10-11 13:08:43 test_zl: DEBUG init start: df_bts = NA
2021-10-11 13:08:43 test_zl: DEBUG init start: df_cross = NA
2021-10-11 13:08:43 test_zl: DEBUG init end: df_init = [0]
2021-10-11 13:08:43 test_zl: DEBUG init end: df_bts = NA
2021-10-11 13:08:43 test_zl: DEBUG init end: df_cross = [0]
2021-10-11 13:08:43 test_zl: DEBUG bts start: df_init = [0]
2021-10-11 13:08:43 test_zl: DEBUG bts start: df_bts = NA
2021-10-11 13:08:43 test_zl: DEBUG bts start: df_cross = [0]
2021-10-11 13:08:43 test_zl: DEBUG bts end: df_init = [0]
2021-10-11 13:08:43 test_zl: DEBUG bts end: df_bts = [0]
2021-10-11 13:08:43 test_zl: DEBUG bts end: df_cross = [0, 1]

Data is saved correctly in joblib file:

import joblib
joblib.load('NAME OF JOBLIB FILE')

{'df_bts': [0], 'df_cross': [0, 1], 'df_init': [0]}

Second run:
2021-10-11 13:11:45 test_zl: DEBUG init start: df_init = NA
2021-10-11 13:11:45 test_zl: DEBUG init start: df_bts = NA
2021-10-11 13:11:45 test_zl: DEBUG init start: df_cross = NA
2021-10-11 13:11:45 test_zl: DEBUG init end: df_init = [0]
2021-10-11 13:11:45 test_zl: DEBUG init end: df_bts = NA
2021-10-11 13:11:45 test_zl: DEBUG init end: df_cross = [0]
2021-10-11 13:11:45 test_zl: DEBUG bts start: df_init = [0]
2021-10-11 13:11:45 test_zl: DEBUG bts start: df_bts = [0]
2021-10-11 13:11:45 test_zl: DEBUG bts start: df_cross = [0, 1]
2021-10-11 13:11:45 test_zl: DEBUG bts end: df_init = [0]
2021-10-11 13:11:45 test_zl: DEBUG bts end: df_bts = [0, 1]
2021-10-11 13:11:45 test_zl: DEBUG bts end: df_cross = [0, 1, 2]

joblib:
{'df_bts': [0, 1], 'df_cross': [0, 1, 2], 'df_init': [0]}

You see that context is not up-to-date in initialize routine but is up-to-date in other procedures. Actually it's according to docs:
"After running initialize() , QuantRocket looks for and loads this joblib file, which will update any context variables set in initialize() to their latest values"
But it's counterintuitive: only first context updates in initialize routine save data. All other runs just ignore your code.

I've made the mistake of trying to change live parameters in initialize() several times also and agree it's not intuitive. Seems to defeat the purpose of the initialize() function in live, while it works great in backtest to avoid running repeat code every simulated day.

@brian Is there a reason that the reading of the context from joblib can't be performed before initialize() executes instead?

The implementation of live trading is designed to mirror backtesting as closely as possible. initialize() doesn’t run on day >= 2 of a backtest, so it wouldn’t make sense to do so in live trading either.

On day >= 2 of live trading, initialize() only runs in order to perform housekeeping tasks like re-instantiating pipelines, which don’t affect state and are required since the algorithm shuts down each night.