Tutorial: Advanced algo strategies with the Python Honey Framework
The Honey Framework Python module is still in experimental stage and it is not recommended to be ran on live markets yet.
A few months ago Bitfinex released a Python port of the popular Honey Framework which helps developers to create refined algo strategies. If this is the first time you have heard of the honey framework then I suggest you head to the original announcement post to get up to date:
We also published a tutorial a few weeks ago explaining the simple concepts of the Honey framework. This tutorial will carry on from where we left of so please read this if you have not already:
So what’s an advanced algo strategy?
In the previous tutorial we looked into creating orders and handling the logical flow that the honey framework provides for us. In this tutorial we are going to up it a notch to see how the Honey Framework can assist to overcome some of the more difficult problems faced when creating advanced strategies.
Now, trading algo’s can be as complex as you wish to make them and it is common for strategies to use tools such as machine learning and external data in order to try and get an edge. This is completely possible with the Honey Framework, since you can use the popular languages (NodeJs and Python) to plug in libraries and program that stuff yourself. But we are going to focus on the special features that the framework provides for us and implement a risk management system which creates dynamic stop losses and profit targets.
Creating a profit/stop target
Handling stop losses and profit target using the Honey Framework is really easy, all we need to do is specify the price and the framework will automatically create the necessary orders (either limit, stop-limit or OCO) to handle the request. Not only that but it will also automatically adjust these values if we decided to add/remove value from our position later on. Firstly we are going to define our entry event function, this will just use the EMA cross to decide whether to enter the market or not:
@strategy.on_enterasync def enter(update): # We are going to use the ema cross for entrance emaS = strategy.get_indicators()['emaS'] emaL = strategy.get_indicators()['emaL'] # enter market if ema crosses if emaS.crossed(emaL.v()): if emaS.v() > emaL.v(): await enter_long(update) else: await enter_short(update)
Once we have decide how to enter the market we can begin to create a more complex entry function that decides the positions of our profit targets and our stop losses:
async def enter_short(update): await strategy.open_short_position_market(mtsCreate=update.mts, amount=1) # same as above, take full proft at 5% profit_target = update.price - (update.price * 0.05) # set stop loss to %2 below entry stop_loss = update.price + (update.price * 0.02) await strategy.set_position_target(profit_target) await strategy.set_position_stop(stop_loss)async def enter_long(update): await strategy.open_long_position_market(mtsCreate=update.mts, amount=1) # set profit target to 5% above entry profit_target = update.price + (update.price * 0.05) # set a tight stop los of %2 below entry stop_loss = update.price - (update.price * 0.02) # update positions with new targets await strategy.set_position_target(profit_target) await strategy.set_position_stop(stop_loss)
In the above code we create a new long/short position depending on the previous ema cross calculation and then set the position to create a profit target at a 5% gain of the origin entry price and -2% gain stop loss. You can play around with these values or use a more complex method to calculate them, some popular methods involve identifying support/resistance levels or using an indicator such as RSI etc…
Dynamic ‘Take Profit’ levels
A common trading technique is to set a series of profit target levels which, when reached, will reduce the overall size of the position and claim the profits. We are going to implement this kind of feature but also, when we reach our first profit target level, we will also move our position stop loss to our original entry price so we cannot lose money on the position. These kind of risk management features can really help to reduce the average loss of a strategy:
@strategy.on_update_long async def update_long(update, position): emaS = strategy.get_indicators()['emaS'] emaL = strategy.get_indicators()['emaL'] # Market is going to change direction so exit position if emaS.v() < emaL.v(): return await strategy.close_position_market(mtsCreate=update.mts) # Same as above, take profit at 2% and set stop to entry # get entry of initial order entry = position.get_entry_order().price half_position = abs(position.amount)/2 if half_position < 0.1: return if update.price > entry + (position.price * 0.02): print ("Reached profit target, take 2%") await strategy.update_position_market(mtsCreate=update.mts, amount=-half_position, tag="Hit mid profit target") # set our stop loss to be our original entry price await strategy.set_position_stop(entry,exit_type=Position.ExitType.MARKET)
(Apologies for the horrible Medium formatting you can see the original code here)
Here we define our update long position event which will be fired every time a new price update is received and if we have a long open. Firstly, we define a simple exit strategy which is the opposite of our entry, if the ema crosses back over then exit the positionc completely. Next we set some logic that states if the current price reaches more than 2% gain then sell half of our position and set the position stop loss to the orginal entry of the position.
Lets run it!
As you can see when compared to our last tutorial the performance of this strategy has been increased significantly because of the new risk management. The overall gross profit loss has increased from -$165 to a profitable $153.
Thanks for reading!
To run this code yourself please head over to the official repo here and navigate to the examples folder.
For the NodeJS version then head to github.com/bitfinexcom/bfx-hf-strategy.