Using historical metrics to calculate Kelly Optimal f

Hello,

I'm trying to create a code to size positions according to Kelly Optimal f from this formula:

f = [p x (PLR + 1) - 1] / PLR, where

PLR = the ratio of average profit to average loss
p = the probability of a winning trade.

I am new when it comes to custom backtest, I was checking the information in the website and the forum but I still can't figure out how to get the stats for trading out of the custom backtest. Probably it's quite simple, I would thank some help about it.

For example, I can get the graphic representation of the stats that I need, according to the following entry: https://www.amibroker.com/kb/2008/05/19/historical-portfolio-backtest-metrics/, the code would be like this one (to easy the code, I buy all the 100 symbols from a category and rebalance them annualy):

/// --- CustomBacktest ---

SetOption("UseCustomBacktestProc", True ); 

if( Status("action") == actionPortfolio )
{
  bo = GetBacktesterObject();
  bo.PreProcess(); 

  WinnersPercent   = Null;
  WinnersAvgProfit = Null; 
  LosersAvgLoss    = Null; 

  for(bar=0; bar < BarCount; bar++)
  {
  bo.ProcessTradeSignals( bar );
  stats = bo.GetPerformanceStats( 0 ); 
 
  WinnersPercent[bar]   = stats.GetValue("WinnersPercent");
  WinnersAvgProfit[bar] = stats.GetValue("WinnersAvgProfit"); 
  LosersAvgLoss[bar]    = stats.GetValue("LosersAvgLoss"); 
  }
  bo.PostProcess(); 

  AddToComposite( WinnersPercent, "~~~WinnersPercent_Historical", "X", atcFlagEnableInPortfolio | atcFlagDefaults );
  AddToComposite( WinnersAvgProfit, "~~~WinnersAvgProfit_Historical", "X", atcFlagEnableInPortfolio | atcFlagDefaults );
  AddToComposite( LosersAvgLoss, "~~~LosersAvgLoss_Historical", "X", atcFlagEnableInPortfolio | atcFlagDefaults );
  } 

/// --- Trading Rules ---

Rebalance = Year() != Ref(Year(), -1);

Buy = 1;
Sell = Rebalance;

SetPositionSize(1/100; spsPercentOfEquity);

/// --- Graph ---

PlotForeign("~~~WinnersPercent_Historical", "WinnersPercen", colorRed, styleLine );
PlotForeign("~~~WinnersAvgProfit_Historical", "WinnersAvgProfit", colorBlue, styleLine );
PlotForeign("~~~LosersAvgLoss_Historical", "WinnersAvgProf", colorBlack, styleLine );

What I would need to do is what is represented next (I write the code in a conceptual way, of course it doesn't work)

/// --- Trading Rules ---

Rebalance = Year() != Ref(Year(), -1);

Buy = 1;
Sell = Rebalance;

WinningTradeProbability = WinnersPercent;
AverageProfitLossRatio  = WinnersAvgProfit / LosersAvgLoss;


Optimalf        = ((WinningTradeProbability * (AverageProfitLossRatio + 1))-1) / AverageProfitLossRatio;
DilutedOptimalf = DilutedOptimalf * 0.1;

SetPositionSize(Optimalf, spsPercentOfEquity);

Finally, the question is how to get the WinnersPercent, WinnersAvgProfit and LosersAvgLoss for each bar from the custom backtest section, so that I can use them for sizing the position of new trades.

Thank you beforehand.

Best regards.

1 Like

If I am correct, Kelly gives you the fraction of available equity to risk, not the amount to invest. I have seen this confusion in the past. Since Kelly is the fraction to risk, you will need to calculate the equity for each security and then determine Kelly for each security based on its win fraction and payoff ratio. Then based on the result, calculate the number of shares to buy if less than maximum allowable shares. But to calculate the number of shares from the Kelly fraction, you will need to assume a stop-loss. I suspect what you need is the Kelly leverage, not the Kelly fraction. But that always comes higher than full allocation in most cases. It is interesting problem.

makhar88,

Thanks for your answer.

You're right, I was making a mistake about the application ot the Optimal f. When it comes to the available equity to risk, I guess we could use the following approach: https://www.amibroker.com/kb/2014/10/12/position-sizing-based-on-risk/

I modify the code according to it:

/// --- Trading Rules ---

Rebalance = Year() != Ref(Year(), -1);

Buy = 1;
Sell = Rebalance;

RiskPerShare =  2 * ATR( 20 );
ApplyStop( stopTypeLoss, stopModePoint, RiskPerShare, True );

WinningTradeProbability = WinnersPercent;
AverageProfitLossRatio  = WinnersAvgProfit / LosersAvgLoss;

Optimalf        = ((WinningTradeProbability * (AverageProfitLossRatio + 1))-1) / AverageProfitLossRatio;
DilutedOptimalf = Optimalf * 0.1;

PctSize =  DilutedOptimalf  * BuyPrice / RiskPerShare;
SetPositionSize(PctSize, spsPercentOfEquity );

Anyway, I'm stuck with extracting the metrics from the custom backtest to use them for trading in each bar. I hope someone would help me with that.

Best regards

1 Like

Here is what I use to calculate the win rate. Maybe that helps:

SetOption( "ExtraColumnsLocation", 9 ); 
SetCustomBacktestProc( "" ); 
if ( Status( "action" ) == actionPortfolio ) { 
    bo = GetBacktesterObject(); 
    bo.Backtest(1); 

    sumprofit = 0; 
    trades = 0; 
    
    // iterate through closed trades
    for ( trade = bo.GetFirstTrade(); trade; trade = bo.GetNextTrade() ) { 
        profit = trade.GetProfit(); 
        trades++; 
        if ( profit > 0 ) { 
            sumprofit++; 
        } 
        WinRate = sumprofit / trades * 100; 
        trade.AddCustomMetric( "WinRate(%)", WinRate, DecPlaces = 2 );   
    } 
    // iterate through open positions 
    for ( trade = bo.GetFirstOpenPos(); trade; trade = bo.GetNextOpenPos() ) { 
        profit = trade.GetProfit(); 
        trades++; 
        if ( profit > 0 ) { 
            sumprofit++; 
        }         
        WinRate = sumprofit / trades * 100; 
        trade.AddCustomMetric( "WinRate(%)", WinRate, DecPlaces );   
       Plot(WinRate, "Win Rate", colorBlack, styleLine);
    } 
    bo.ListTrades(); 
} 

Of course credit to @fxstrat

1 Like

I am also trying to solve the same problem that you are having. I have not yet found a solution, but I think this link might be very helpful

I would think that here:

PctSize =  DilutedOptimalf  * BuyPrice / RiskPerShare;

You have to multiply by available equity, Equity(), and divide by BuyPrice x RiskPerShare.

If I am not wrong (I am frequently) :slight_smile:

I did not post that code.
I would never place Plot function within CBT code and not within such loop.

1 Like

So @fxshrat is now being credited for the code he did not write. LOL :smile:

2 Likes

Perhaps I should run for US presidency next time. :smiley:

3 Likes

makhar88,

Thanks for your answer.

Sorry to persist in my doubt, probably the solution to my problem is quite simple but I can't see it yet.

I will add some basic trading rules to your code, just to set the example

SetOption( "ExtraColumnsLocation", 9 ); 
SetCustomBacktestProc( "" ); 
if ( Status( "action" ) == actionPortfolio ) { 
    bo = GetBacktesterObject(); 
    bo.Backtest(1); 

    sumprofit = 0; 
    trades = 0; 
    
    // iterate through closed trades
    for ( trade = bo.GetFirstTrade(); trade; trade = bo.GetNextTrade() ) { 
        profit = trade.GetProfit(); 
        trades++; 
        if ( profit > 0 ) { 
            sumprofit++; 
        } 
        WinRate = sumprofit / trades * 100; 
        trade.AddCustomMetric( "WinRate(%)", WinRate, DecPlaces = 2 ); 
        StaticVarSet("WinRate", WinRate);  
    } 
    bo.ListTrades(); 
} 

/// --- Trading Rules ---

Rebalance = Year() != Ref(Year(), -1);

Buy = 1;
Sell = Rebalance;
Winrate = StaticVarGet("Winrate");

SetPositionSize(Winrate, spsPercentOfEquity );

I would need to take out Winrate for trading on each bar, and I'm unable to do that, I have tried on different ways.

Any help will be welcomed

Best regards.

Right, I posted the wrong code, sorry, here is the code you suggested

1 Like

Perhaps I should run for US presidency next time. :smiley:

Would you mind? :wink:

So not sure if it was stated above, but Optimal f is the fraction of equity for whatever the system bet unit is. You can also calculate equity intervals changes (daily or whatever) and make that a "theoretical trade", that way even if your equity changes are portfolio based you can adjust a unit of portfolio size each interval in theory.

While f is a fixed "Fraction", Kelly is expressed as risk per trade. Optimal Kelly is simply equal to expectation (per trade if sequential) or heat, or expectation of equity changes per a given interval. So by whatever measure if expectation equals 1% per whatever, then optimal Kelly is to risk 1% per whatever.

Given @fxshrat coding prowess, he could certainly hack into those vulnerable Dominion voting machines over here. Oops, I guess I just gave away my political leanings. ;)~
@fxshrat for president!

-S

This topic was automatically closed 100 days after the last reply. New replies are no longer allowed.