17. 1. 2022

5 0

Biggest MAE on multiple trades

We have a snippet “Biggest MAE“.
It is very useful to see how a strategy with a single order behave.

By experience, I noticed often that it is more efficient to work with a basket of orders instead of a single order. For example, it is wiser to spread 1 % of risk on a basket of orders, instead of the full 1% on a single order.

With a a basket or orders, you have more flexibility as you can choose multiple entry positions. You don’t have to pinpoint your single entry position.

If you open multiple orders at once, you have to calculate the total MAE of all the open positions.

This calculus is necessary if you open all positions in the same direction. (no hedging Position)

 

I propose here two snippets : 

The first one : “BiggestMAEallTrade“, is giving you the biggest MAE for ONE contract.  I made the calculus for one contract to have an accurate results even if the strategy increase the contract size during the In Sample period.

From this results, you have a good idea, if you work with 0.1 contract size for example.

 

package SQ.Columns.Databanks;

import com.strategyquant.lib.L;
import com.strategyquant.lib.SQUtils;
import com.strategyquant.lib.SettingsMap;
import com.strategyquant.tradinglib.*;

import java.util.List;
import java.util.ArrayList;
import java.util.*;
import java.lang.*;  

// Mode in France by Emmanuel Evrard for the StrategyQuantX Community :)
public class BiggestMAEallTrade extends DatabankColumn 
{
    public BiggestMAEallTrade() 
    {
        super(L.tsq("Biggest Multiple MAE"), DatabankColumn.Decimal2PL, ValueTypes.Minimize, 0, 0, 100);

        setWidth(140);
        
        setTooltip(L.tsq("Biggest Multiple MAE - is the worst Maximum Adverse Excursion of all trades open at once"));
    }
    
    //------------------------------------------------------------------------

    @Override
    public double compute(SQStats stats, StatsTypeCombination combination, OrdersList ordersList, SettingsMap settings, SQStats statsLong, SQStats statsShort) throws Exception 
    {
        double worstMAE = -Double.MAX_VALUE;
        Date date = new Date();
        Date dateTemp = new Date();
        double Total1 = 0;
        double Size1 = 0;

        for(int i = 0; i<ordersList.size(); i++) 
        {
            Order order = ordersList.get(i);
            dateTemp = new Date(order.CloseTime);
            Size1 = order.Size;
            if (Size1 == 0) { Size1 = 0.01; }

            if (dateTemp.equals(date))
            {
                Total1 += order.MAE;
            }
            else
            {
                date = new Date(order.CloseTime);
                Total1 = order.MAE;
            }

            if((Total1 / Size1)  > worstMAE) 
            {
                worstMAE = (Total1/order.Size);
            }
        }
        
        return -1*worstMAE;
    }
}

 

The second one : “BiggestMAEallTradePct“, is giving the biggest MAE compared to AccountBalance, This is interesting to see if a strategy use not enough or need too much of the Account Balance.

If you have a 5% Max daily Loss, you can see if you are above it or under it.

 

package SQ.Columns.Databanks;

import com.strategyquant.lib.L;
import com.strategyquant.lib.SQUtils;
import com.strategyquant.lib.SettingsMap;
import com.strategyquant.tradinglib.*;

import java.util.List;
import java.util.ArrayList;
import java.util.*;
import java.lang.*;  

// Mode in France by Emmanuel Evrard for the StrategyQuantX Community :)
public class BiggestMAEallTradePct extends DatabankColumn 
{
    public BiggestMAEallTradePct() 
    {
        super(L.tsq("Biggest Multiple MAE %"), DatabankColumn.Decimal2Pct, ValueTypes.Minimize, 0, 0, 100);
        setWidth(70);
        setTooltip(L.tsq("Biggest Multiple MAE % - is the worst Maximum Adverse Excursion of all trades open at once compared to AccountBalance"));
    }
    
    @Override
    public double compute(SQStats stats, StatsTypeCombination combination, OrdersList ordersList, SettingsMap settings, SQStats statsLong, SQStats statsShort) throws Exception 
    {
        double worstMAE = -Double.MAX_VALUE;
        Date date = new Date();
        Date dateTemp = new Date();
        double Total1 = 0;
        double Total2 = 0;

        for(int i = 0; i<ordersList.size(); i++) 
        {
            Order order = ordersList.get(i);
            dateTemp = new Date(order.CloseTime);

            if (dateTemp.equals(date))
            {
                Total1 += order.MAE;
            }
            else
            {
                date = new Date(order.CloseTime);
                Total1 = order.MAE;
            }
            Total2 = SQUtils.safeDivide(Total1, order.AccountBalance - order.PL) * 100.0;
            if(Total2  > worstMAE) 
            {
                worstMAE = Total2;
            }
        }

        return -1*worstMAE;
    }
}


If you have multiple positions on opposite direction, bullish and bearish, in this case , it could be interesting to have a different calculus :

I took the larger MAE and subtract the MFE of the opposite direction to get the global MAE of this biggest MAE.

This is working only if the opposite trades are open during the larger MAE and not after. However this calculus may be useful.

I made these modifications in snippets BiggestMAEallHedgingTrade and BiggestMAEallHedgingTradePct

 

 

package SQ.Columns.Databanks;

import com.strategyquant.lib.L;
import com.strategyquant.lib.SQUtils;
import com.strategyquant.lib.SettingsMap;
import com.strategyquant.tradinglib.*;

import java.util.List;
import java.util.ArrayList;
import java.util.*;
import java.lang.*;  

// Mode in France by Emmanuel Evrard for the StrategyQuantX Community :)
public class BiggestMAEallHedgingTrade extends DatabankColumn 
{
    public BiggestMAEallHedgingTrade() 
    {
        super(L.tsq("Biggest Multiple Hedging MAE"), DatabankColumn.Decimal2PL, ValueTypes.Minimize, 0, 0, 100);

        setWidth(140);
        
        setTooltip(L.tsq("Biggest Multiple Hedging MAE - is the worst Maximum Adverse Excursion of all trades open at once"));
    }
    
    //------------------------------------------------------------------------

    @Override
    public double compute(SQStats stats, StatsTypeCombination combination, OrdersList ordersList, SettingsMap settings, SQStats statsLong, SQStats statsShort) throws Exception 
    {
        double worstMAE1= -Double.MAX_VALUE;
        double worstMAE2 = -Double.MAX_VALUE;
        double BesttMFE1= -Double.MAX_VALUE;

        Date date = new Date();
        Date dateTemp = new Date();
        double Total1 = 0;
        double Size1 = 0;
        int direction = 0;

        for(int i = 0; i < ordersList.size(); i++) 
        {
            Order order = ordersList.get(i);
            dateTemp = new Date(order.CloseTime);
            Size1 = order.Size;
            direction=order.getDirection();

            if (direction == 1)     								// Bullish positions
            {
                if (Size1 == 0) { Size1 = 0.01; }

                if (dateTemp.equals(date))
                {
                    Total1 += order.MAE;
                }
                else
                {
                    date = new Date(order.CloseTime);
                    Total1 = order.MAE;
                }

                if((Total1 / Size1)  > worstMAE1) 
                {
                    worstMAE1 = (Total1/order.Size);
                }
            }
        }

        Total1 = 0;
        for(int i = 0; i < ordersList.size(); i++) 
        {
            Order order = ordersList.get(i);
            dateTemp = new Date(order.CloseTime);
            Size1 = order.Size;
            direction=order.getDirection();

            if (direction == -1)     								// Bearish positions
            {
                if (Size1 == 0) { Size1 = 0.01; }

                if (dateTemp.equals(date))
                {
                    Total1 += order.MAE;
                }
                else
                {
                    date = new Date(order.CloseTime);
                    Total1 = order.MAE;
                }

                if((Total1 / Size1)  > worstMAE2) 
                {
                    worstMAE2 = (Total1/order.Size);
                }
            }
        }
        
        if (worstMAE1 >= worstMAE2)
        {
            Total1 = 0;
            for(int i = 0; i < ordersList.size(); i++) 
            {
                Order order = ordersList.get(i);
                dateTemp = new Date(order.CloseTime);
                Size1 = order.Size;
                direction=order.getDirection();

                if (direction == -1)     								// Bearish positions
                {
                    if (Size1 == 0) { Size1 = 0.01; }

                    if (dateTemp.equals(date))
                    {
                        Total1 += order.MFE;
                    }
                    else
                    {
                        date = new Date(order.CloseTime);
                        Total1 = order.MFE;
                    }

                    if((Total1 / Size1)  > BesttMFE1) 
                    {
                        BesttMFE1 = (Total1/order.Size);
                    }
                }
            }

            return -1*(worstMAE1 - BesttMFE1);
        }
        else if (worstMAE2 > worstMAE1)
        {
            Total1 = 0;
            for(int i = 0; i < ordersList.size(); i++) 
            {
                Order order = ordersList.get(i);
                dateTemp = new Date(order.CloseTime);
                Size1 = order.Size;
                direction=order.getDirection();

                if (direction == 1)     								// Bullish positions
                {
                    if (Size1 == 0) { Size1 = 0.01; }

                    if (dateTemp.equals(date))
                    {
                        Total1 += order.MFE;
                    }
                    else
                    {
                        date = new Date(order.CloseTime);
                        Total1 = order.MFE;
                    }

                    if((Total1 / Size1)  > BesttMFE1) 
                    {
                        BesttMFE1 = (Total1/order.Size);
                    }
                }
            }

            return -1*(worstMAE2 - BesttMFE1);
        }
        return 0;
    }
}

package SQ.Columns.Databanks;

import com.strategyquant.lib.L;
import com.strategyquant.lib.SQUtils;
import com.strategyquant.lib.SettingsMap;
import com.strategyquant.tradinglib.*;

import java.util.List;
import java.util.ArrayList;
import java.util.*;
import java.lang.*;  

// Mode in France by Emmanuel Evrard for the StrategyQuantX Community :)
public class BiggestMAEallHedgingTradePct extends DatabankColumn 
{
    public BiggestMAEallHedgingTradePct() 
    {
        super(L.tsq("Biggest Multiple Hedging MAE %"), DatabankColumn.Decimal2Pct, ValueTypes.Minimize, 0, 0, 100);
        setWidth(100);
        setTooltip(L.tsq("Biggest Multiple Hedging MAE % - is the worst Maximum Adverse Excursion of all trades open at once compared to AccountBalance"));
    }
    
    @Override
    public double compute(SQStats stats, StatsTypeCombination combination, OrdersList ordersList, SettingsMap settings, SQStats statsLong, SQStats statsShort) throws Exception 
    {
        double worstMAE1= -Double.MAX_VALUE;
        double worstMAE2 = -Double.MAX_VALUE;
        double BesttMFE1= -Double.MAX_VALUE;
        Date date = new Date();
        Date dateTemp = new Date();
        double Total1 = 0;
        double Total2 = 0;
        int direction = 0;

        for(int i = 0; i<ordersList.size(); i++) 
        {
            Order order = ordersList.get(i);
            dateTemp = new Date(order.CloseTime);
            direction=order.getDirection();

            if (direction == 1)      								// Bullish position
            {
                if (dateTemp.equals(date))
                {
                    Total1 += order.MAE;
                }
                else
                {
                    date = new Date(order.CloseTime);
                    Total1 = order.MAE;
                }
                Total2 = SQUtils.safeDivide(Total1, order.AccountBalance - order.PL) * 100.0;
                if(Total2  > worstMAE1) 
                {
                    worstMAE1 = Total2;
                }
            }
        }

        Total1 = 0;
        for(int i = 0; i<ordersList.size(); i++) 
        {
            Order order = ordersList.get(i);
            dateTemp = new Date(order.CloseTime);
            direction=order.getDirection();
            
            if (direction == -1)      								// Bearish position
            {
                if (dateTemp.equals(date))
                {
                    Total1 += order.MAE;
                }
                else
                {
                    date = new Date(order.CloseTime);
                    Total1 = order.MAE;
                }
                Total2 = SQUtils.safeDivide(Total1, order.AccountBalance - order.PL) * 100.0;
                if(Total2  > worstMAE2) 
                {
                    worstMAE2 = Total2;
                }
            }
        }

        if (worstMAE1 >= worstMAE2)
        {
            Total1 = 0;
            for(int i = 0; i<ordersList.size(); i++) 
            {
                Order order = ordersList.get(i);
                dateTemp = new Date(order.CloseTime);
                direction=order.getDirection();
                
                if (direction == -1)      								// Bearish position
                {
                    if (dateTemp.equals(date))
                    {
                        Total1 += order.MFE;
                    }
                    else
                    {
                        date = new Date(order.CloseTime);
                        Total1 = order.MFE;
                    }
                    Total2 = SQUtils.safeDivide(Total1, order.AccountBalance - order.PL) * 100.0;
                    if(Total2  > BesttMFE1) 
                    {
                        BesttMFE1 = Total2;
                    }
                }
            }

            return -1*(worstMAE1 - BesttMFE1);
        }
        else if (worstMAE2 > worstMAE1)
        {
            Total1 = 0;
            for(int i = 0; i<ordersList.size(); i++) 
            {
                Order order = ordersList.get(i);
                dateTemp = new Date(order.CloseTime);
                direction=order.getDirection();

                if (direction == 1)      								// Bullish position
                {
                    if (dateTemp.equals(date))
                    {
                        Total1 += order.MFE;
                    }
                    else
                    {
                        date = new Date(order.CloseTime);
                        Total1 = order.MFE;
                    }
                    Total2 = SQUtils.safeDivide(Total1, order.AccountBalance - order.PL) * 100.0;
                    if(Total2  > BesttMFE1) 
                    {
                        BesttMFE1 = Total2;
                    }
                }
            }
            return -1*(worstMAE2 - BesttMFE1);
        }
        return 0;
    }
}

 

 

 

Subscribe
Notify of
0 Comments
Inline Feedbacks
View all comments