Skip to content

Examples

To get you started we prepared a few examples of how to approach certain scenarios often used in trading.

For working strategies check out these repositories:

Crossovers

Let's try to catch the moment the price moves above the bollinger middleband.

py
@property  
def long_cross(self):  
    return self.price > self.bb.middleband[-1] and self.candles[:, 2][-2] <= self.bb.middleband[-2]  
  
@property  
def bb(self):  
    return ta.bollinger_bands(self.candles, sequential=True)
@property  
def long_cross(self):  
    return self.price > self.bb.middleband[-1] and self.candles[:, 2][-2] <= self.bb.middleband[-2]  
  
@property  
def bb(self):  
    return ta.bollinger_bands(self.candles, sequential=True)

As alternative you could use the crossed utility:

py
@property  
def long_cross(self):  
    return utils.crossed(self.candles[:, 2], self.bb.middleband, 'above')  
  
@property  
def bb(self):  
    return ta.bollinger_bands(self.candles, sequential=True)
@property  
def long_cross(self):  
    return utils.crossed(self.candles[:, 2], self.bb.middleband, 'above')  
  
@property  
def bb(self):  
    return ta.bollinger_bands(self.candles, sequential=True)

Stoploss / Take Profit

Simple ATR:

py
def go_long(self):  
    take_profit = self.price + self.atr * 3  
    stop = self.price - self.atr * 2  
    qty = 10
    self.buy = qty, self.price  
    self.stop_loss = qty, stop  
    self.take_profit = qty, take_profit  
  
  
@property  
def atr(self):  
    return ta.atr(self.candles, period=22)
def go_long(self):  
    take_profit = self.price + self.atr * 3  
    stop = self.price - self.atr * 2  
    qty = 10
    self.buy = qty, self.price  
    self.stop_loss = qty, stop  
    self.take_profit = qty, take_profit  
  
  
@property  
def atr(self):  
    return ta.atr(self.candles, period=22)

A trailing stop:

py
def update_position(self):  
    # update trailing_stop_loss only if in profit  
    if self.position.pnl > 0:  
        if self.is_long:  
            self.stop_loss = self.position.qty, self.price - self.atr * 2  
        else:  
            self.stop_loss = self.position.qty, self.price + self.atr * 2
def update_position(self):  
    # update trailing_stop_loss only if in profit  
    if self.position.pnl > 0:  
        if self.is_long:  
            self.stop_loss = self.position.qty, self.price - self.atr * 2  
        else:  
            self.stop_loss = self.position.qty, self.price + self.atr * 2

You also can use Moving Averages to exit once they are hit.

py
def update_position(self):  
    if self.is_long and self.price <= self.exit_ema:  
       self.liquidate()  
       
@property  
def exit_ema(self):  
    return ta.ema(self.candles)
def update_position(self):  
    if self.is_long and self.price <= self.exit_ema:  
       self.liquidate()  
       
@property  
def exit_ema(self):  
    return ta.ema(self.candles)

Special indicators you might want to try for your exits:

Channels can also be good for stoploss or take profit:

Getting the size right

This example might help with the position size/qty. We use risk management. There might be situations where risk_to_qty returns a qty exceeding the available capital leading to an exception. The reason for this is a very close stop loss (often due to the usage of the ATR). That's not an error, but the expected behavior of the formula. We add a logic limiting the qty to a maximum percentage (in this case 25 %) of the capital for those cases.

py
  
def go_long(self):  
    stop = self.bb.lowerband
    qty = self.position_size(self.price, stop)  
    take_profit = self.bb.upperband
    self.buy = qty, self.price  
    self.stop_loss = qty, stop  
    self.take_profit = qty, take_profit  
  
@property  
def position_size(self, entry, stop):  
    # risk 10%
    risk_qty = utils.risk_to_qty(self.balance, 10, entry, stop, fee_rate=self.fee_rate)  
    # never risk more than 25% of the capital
    max_qty = utils.size_to_qty(0.25 * self.balance, entry, precision=6, fee_rate=self.fee_rate)  
    qty = min(risk_qty, max_qty) 
    return qty
  
def go_long(self):  
    stop = self.bb.lowerband
    qty = self.position_size(self.price, stop)  
    take_profit = self.bb.upperband
    self.buy = qty, self.price  
    self.stop_loss = qty, stop  
    self.take_profit = qty, take_profit  
  
@property  
def position_size(self, entry, stop):  
    # risk 10%
    risk_qty = utils.risk_to_qty(self.balance, 10, entry, stop, fee_rate=self.fee_rate)  
    # never risk more than 25% of the capital
    max_qty = utils.size_to_qty(0.25 * self.balance, entry, precision=6, fee_rate=self.fee_rate)  
    qty = min(risk_qty, max_qty) 
    return qty

Using the kelly criterion:

py
def kelly_qty(self, entry, stop):  
    if not self.metrics or self.metrics['total'] < 20:  
        win_rate = 0.46  
        ratio_avg_win_loss = 1.6  
    else:  
        win_rate = self.metrics['win_rate']  
        ratio_avg_win_loss = self.metrics['ratio_avg_win_loss']  
    kc = utils.kelly_criterion(win_rate, ratio_avg_win_loss) * 100  
    if not kc or kc <= 0:  
        raise ValueError("Bad Kelly criterion.")  
    risk_qty = utils.risk_to_qty(self.available_margin, kc, entry, stop, self.fee_rate)  
    # never risk more than 25%  
    max_qty = utils.size_to_qty(0.25 * self.available_margin, entry, precision=6, fee_rate=self.fee_rate)  
    qty = min(risk_qty, max_qty)  
    return qty
def kelly_qty(self, entry, stop):  
    if not self.metrics or self.metrics['total'] < 20:  
        win_rate = 0.46  
        ratio_avg_win_loss = 1.6  
    else:  
        win_rate = self.metrics['win_rate']  
        ratio_avg_win_loss = self.metrics['ratio_avg_win_loss']  
    kc = utils.kelly_criterion(win_rate, ratio_avg_win_loss) * 100  
    if not kc or kc <= 0:  
        raise ValueError("Bad Kelly criterion.")  
    risk_qty = utils.risk_to_qty(self.available_margin, kc, entry, stop, self.fee_rate)  
    # never risk more than 25%  
    max_qty = utils.size_to_qty(0.25 * self.available_margin, entry, precision=6, fee_rate=self.fee_rate)  
    qty = min(risk_qty, max_qty)  
    return qty

We need to check for a minimum of trades so we have a good win_rate and ratio_avg_win_loss to work with. In this case, we use 20 trades. For those first trades we use hardcoded values, we got from backtests. win_rate is the same as Percent Profitable / 100. ratio_avg_win_loss is called Ratio Avg Win / Avg Loss.

We do NOT guarantee profitable trading results in anyways. USE THE SOFTWARE AT YOUR OWN RISK. THE AUTHORS AND ALL AFFILIATES ASSUME NO RESPONSIBILITY FOR YOUR TRADING RESULTS. Do not risk money which you are afraid to lose. There might be bugs in the code - this software DOES NOT come with ANY warranty. All investments carry risk! Past performance is no guarantee of future results! Be aware of overfitting!