Strategy Event Lifecycle
With the Strategy class, we often want to be able to run some code BEFORE a specific price event occurs (such as gather data, initialize variables into the state, store existing open orders if the model is running live), and we often want to run something AFTER the model finishes (close all outstanding positions say for a grid bot, send all trades to a database, etc.)
In order to do this. Strategies have a specific lifecycle on a per price event basis. This allows you to use the same function across multiple price events (such as one init
function that's used everywhere). Or create separate init
functions for each and every price event.
The Strategy Object
Now let's look at a specific example of a strategy that has as price event (note this is the same for bar_event
and other events as well)
from blankly import CoinbasePro, Strategy
def custom_price_event(price, symbol, state):
# do something here
# Authenticate coinbase pro strategy
coinbase_pro = blankly.CoinbasePro()
# Use our strategy helper on coinbase pro
strategy = blankly.Strategy(coinbase_pro)
strategy.add_price_event(custom_price_event, 'BTC-USD', resolution='1h')
strategy.start()
This looks pretty straightforward, but unfortunately, there isn't much that we can do. Why? Because we need to initialize some historical data so that we can calculate rolling values and information. In order to do this, we create an additional init
function.
Init Function
from blankly import CoinbasePro, Strategy, StrategyState
def init(symbol, state: StrategyState):
pass
def custom_price_event(price, symbol, state: StrategyState):
# do something here
# Authenticate coinbase pro strategy
coinbase_pro = blankly.CoinbasePro()
# Use our strategy helper on coinbase pro
strategy = blankly.Strategy(coinbase_pro)
strategy.add_price_event(custom_price_event, 'BTC-USD', resolution='1h')
strategy.start()
This init function allows us to initialize anything that we'd like. Almost every example that we have, always initialize things like "do we have a position?" "what's my stop loss", and of course "my historical data".
def init(symbol, state: StrategyState):
# get last 150 data points
state.variables['history'] = state.interface.history(symbol, 150, state.resolution)
state.variables['has_position'] = False
state.variables['TP'] = 0
...
Now, all we have to do is add this to our price events that we want to initialize.
from blankly import CoinbasePro, Strategy, StrategyState
def init(symbol, state: StrategyState):
# get last 150 data points
state.variables['history'] = state.interface.history(symbol, 150, state.resolution)
state.variables['has_position'] = False
state.variables['TP'] = 0
...
def custom_price_event(price, symbol, state: StrategyState):
# do something here
# Authenticate coinbase pro strategy
coinbase_pro = blankly.CoinbasePro()
# Use our strategy helper on coinbase pro
strategy = blankly.Strategy(coinbase_pro)
strategy.add_price_event(custom_price_event, 'BTC-USD', resolution='1h', init=init)
strategy.add_price_event(custom_price_event, 'ETH-USD', resolution='1h', init=init)
strategy.start()
Teardown Function
And we would do the same with a teardown
function
from blankly import CoinbasePro, Strategy, StrategyState
def init(symbol, state: StrategyState):
# get last 150 data points
state.variables['history'] = state.interface.history(symbol, 150, state.resolution)
state.variables['has_position'] = False
state.variables['TP'] = 0
...
def teardown(symbol, state: StrategyState):
if state.variables['has_position']:
state.interface.market_order(symbol, 'sell', interface.account[symbol].available)
def custom_price_event(price, symbol, state: StrategyState):
# do something here
# Authenticate coinbase pro strategy
coinbase_pro = blankly.CoinbasePro()
# Use our strategy helper on coinbase pro
strategy = blankly.Strategy(coinbase_pro)
strategy.add_price_event(custom_price_event, 'BTC-USD', resolution='1h', init=init, teardown=teardown)
strategy.add_price_event(custom_price_event, 'ETH-USD', resolution='1h', init=init, teardown=teardown)
strategy.start()