As an Amazon Associate I earn from qualifying purchases.
Successful traders focus on how much they are going to (or willing) to lose rather than how much profit they will make. Limiting your risk is vital to the success of your algorithmic trading bot. Today, I will be covering trade management for your algorithmic trading bot.
Here is a quick reminder of what topic I have covered so far in creating an algorithmic trading bot:
- Open a trade using the MT5 API with Python
- Close a trade with MT5 using Python
- Creating an algotrader/trading bot with Python – Part 1
- Creating an algotrader/trading bot with Python – Part 2
- Creating an algotrader/trading bot with Python – Part 3
- Creating a strategy for your algorithmic trading bot – Part 1
- Creating a strategy for your algorithmic trading bot – Part 2
- Dynamically calculate lot size for your algorithmic trading bot
- Send messages from Python to Slack
- Send an email from Python
Getting the closed trades history
Let’s start by implementing a new method from the MT5 API that will allow you to retrieve all previously closed trades and the profit. This is important as we will be using this to calculate the lost trades for the current day. You will be using a method called history_deals_get
from the MT5 API which takes the following arguments: date_from
, date_to
and an option parameter group
which we will not be using today.
Create a new method in trader.py
and name it get_order_history
with arguments date_from
and date_to
:
def get_order_history(date_from, date_to):
Now, make a call to the MT5 API history_deals_get
with the date_from
and date_to
arguments and assign it to a variable named res
:
def get_order_history(date_from, date_to):
res = mt5.history_deals_get(date_from, date_to)
Since res
can be None
or empty
you need to account for this. If res
is not empty then convert the result to data frame and set the time
field to a datetime
type. Otherwise, return an empty data frame.
def get_order_history(date_from, date_to):
res = mt5.history_deals_get(date_from, date_to)
if(res is not None and res != ()):
df = pd.DataFrame(list(res),columns=res[0]._asdict().keys())
df['time'] = pd.to_datetime(df['time'], unit='s')
return df
return pd.DataFrame()
Calculating lost trades per day
To manage our trades you will be checking to see how many trades you have lost in the current day. Start by creating a new method and name it calc_daily_lost_trades
with no arguments:
def calc_daily_lost_trades():
Calculate the current date and time and adjust this for your broker time. Remember, your broker time is not necessarily the same as your local time. Since my broker is in Athens, I will convert the time to this particular timezone. A full last of pytz time zones can be found here.
now = datetime.now().astimezone(pytz.timezone('Europe/Athens'))
Since we are calculating daily losses we need to define midnight as the start of the trading day:
midnight = now.replace(hour=0, minute=0, second=0, microsecond=0)
Call the method get_order_history
created above with midnight
as the first argument and now
as the second and assign it to a variable named res
. This will give us all the closed trades for the current day from midnight:
def calc_daily_lost_trades():
now = datetime.now().astimezone(pytz.timezone('Europe/Athens'))
midnight = now.replace(hour=0, minute=0, second=0, microsecond=0)
res = get_order_history(midnight, now)
If res is empty then we know that no trades have been closed. In this case we can simply return 0.
def calc_daily_lost_trades():
now = datetime.now().astimezone(pytz.timezone('Europe/Athens'))
midnight = now.replace(hour=0, minute=0, second=0, microsecond=0)
res = get_order_history(midnight, now)
if(res.empty):
return 0
Otherwise, let’s iterate over the rows in res and find out what the profit/loss was for each trade. Start by defining a variable named lost_trade_count
for lost trades and a loop to iterate over the rows:
def calc_daily_lost_trades():
now = datetime.now().astimezone(pytz.timezone('Europe/Athens'))
midnight = now.replace(hour=0, minute=0, second=0, microsecond=0)
res = get_order_history(midnight, now)
if(res.empty):
return 0
else:
lost_trade_count = 0
for i, row in res.iterrows():
Find the profit
field in the res
data frame and add an if condition
to say that if profit is less than zero (i.e. a losing trade) increase the lost_trade_count
by 1:
def calc_daily_lost_trades():
now = datetime.now().astimezone(pytz.timezone('Europe/Athens'))
midnight = now.replace(hour=0, minute=0, second=0, microsecond=0)
res = get_order_history(midnight, now)
if(res.empty):
return 0
else:
lost_trade_count = 0
for i, row in res.iterrows():
profit = float(row['profit'])
if(profit < 0):
lost_trade_count = lost_trade_count + 1
Finally, return lost_trade_count
def calc_daily_lost_trades():
now = datetime.now().astimezone(pytz.timezone('Europe/Athens'))
now = datetime(now.year, now.month, now.day, hour=now.hour, minute=now.minute)
midnight = now.replace(hour=0, minute=0, second=0, microsecond=0)
res = get_order_history(midnight, now)
if(res.empty):
return 0
else:
lost_trade_count = 0
for i, row in res.iterrows():
profit = float(row['profit'])
if(profit < 0):
lost_trade_count = lost_trade_count + 1
return lost_trade_count
Limiting your trading exposure
Now that we have a way to calculate daily losses, let’s see how we can use this to our advantage and only open trades if we have not exceeded the maximum allowed daily losses. Start by navigating to the check_trades
method and find the code below:
for index, last in last_row.iterrows():
#Exit strategy
if(last['close'] < last['EMA'] and last['close'] > last['SMA']):
close_positon_by_symbol(pair)
#Entry strategy
if(last['close'] > last['EMA'] and last['close'] < last['SMA']):
lot_size = calc_position_size(pair, strategy)
open_position(pair, "BUY", lot_size, float (strategy['takeProfit']), float(strategy['stopLoss']))
Add a check above # Entry strategy
to check the current amount of lost trades against the amount of losing trades you are willing to have in one day. (This value will come from your strategy.json
file.
Call the calc_daily_lost_trades()
method and assign the result to a variable named lost_trade_count
:
for index, last in last_row.iterrows():
#Exit strategy
if(last['close'] < last['EMA'] and last['close'] > last['SMA']):
close_positon_by_symbol(pair)
lost_trade_count = calc_daily_lost_trades()
Add a check to see if lost_trade_count
is greater than your max losses – if it is, then you will want to add a continue
statement as you will only want to close trades from this point on. If the lost_trade_count
is not bigger than the maximum amount of allowable losses then continue to open trades:
for index, last in last_row.iterrows():
#Exit strategy
if(last['close'] < last['EMA'] and last['close'] > last['SMA']):
close_positon_by_symbol(pair)
lost_trade_count = calc_daily_lost_trades()
if(lost_trade_count > strategy['maxLosses']):
print("Daily losses have been exceeded. Not executing any more trades today")
continue
#Entry strategy
if(last['close'] > last['EMA'] and last['close'] < last['SMA']):
lot_size = calc_position_size(pair, strategy)
open_position(pair, "BUY", lot_size, float (strategy['takeProfit']), float(strategy['stopLoss']))
Adding max losses to your strategy
You should now have a way of calculating daily losses and limiting your trading exposure. Now you need to define strategy['maxLosses']
. This can be done in strategy.json
Your strategy will look like this. (if not I recommend going back to the articles where I talk about creating a strategy):
{
"account_currency" : "USD",
"strategy_name": "myStrategy",
"pairs": [
"EURUSD",
"USDCAD",
"GBPUSD"
],
"risk" : 2,
"takeProfit": 700.0,
"stopLoss": 300.0,
"movingAverages": {
"SMA": {
"val": 10,
"aboveBelow": "below"
},
"EMA": {
"val": 50,
"aboveBelow": "above"
}
}
}
Under risk
, add a new key named “maxLosses” and assign a value of 3. This means that if your trader loses more than 3 trades it will not open any more trades for that day.
{
"account_currency" : "USD",
"strategy_name": "myStrategy",
"pairs": [
"EURUSD",
"USDCAD",
"GBPUSD"
],
"risk" : 2,
"maxLosses" : 3,
...
Testing the code
To test this I will open 3 trades manually and close them with losses. I should see a message saying “Daily losses have been exceeded. Not executing any more trades today” if everything is working as expected.
Trading bot started with strategy: strategy
Running trader at 2021-02-05 08:30:00.688101
Connected: Connecting to MT5 Client
Daily losses have been exceeded. Not executing any more trades today
Daily losses have been exceeded. Not executing any more trades today
Daily losses have been exceeded. Not executing any more trades today
As you can see above, since I have hit my daily losses no more trades will be opened for today.
If you are interested in learning more about algo trading and trading systems, I highly recommend reading this book. I have taken some of my own trading ideas and strategies from this book. It also provided me a great insight into effective back testing. Check it out here.
That’s all for now! Check back on Monday to see how you can monitor your P/L throughout the day! As always, if you have any questions or comments please feel free to post them below. Additionally, if you run into any issues please let me know.