Calcola la peggiore Maximum Adverse Excursion combinata quando sono aperte più posizioni contemporaneamente, aiutandoti a quantificare i drawdown nelle strategie di tipo basket entry.
Biggest MAE - utile per analizzare strategie con ordini singoli o multipli.
Ordini multipli vs ordine singolo
È più efficiente distribuire il rischio su un paniere di ordini anziché su un ordine singolo. Le posizioni di ingresso multiple offrono una maggiore flessibilità senza richiedere un posizionamento preciso a ingresso singolo.
Quando si aprono più ordini contemporaneamente nella stessa direzione, calcola la MAE totale di tutte le posizioni aperte. Se le posizioni sono in direzioni opposte (hedging), sottrai la MFE delle posizioni opposte dalla MAE maggiore per ottenere la MAE complessiva.
Quattro snippet
BiggestMAEallTrade - MAE maggiore per un contratto, normalizzata per contratto per risultati accurati anche se la strategia aumenta la dimensione del contratto durante il backtest.
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;
}
}
BiggestMAEallTradePct - MAE maggiore come percentuale del saldo del conto. Mostra se la strategia utilizza un rischio adeguato rispetto al conto (ad es. confrontandolo con una perdita massima giornaliera del 5%).
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;
}
}
BiggestMAEallHedgingTrade e BiggestMAEallHedgingTradePct - Per posizioni con copertura (hedging) in direzioni opposte. Prende la MAE maggiore e sottrae la MFE della direzione opposta. Funziona quando le operazioni opposte sono aperte durante la MAE maggiore.
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;
}
}