How to write GetFitness

Created at 31 Oct 2023, 08:04
How’s your experience with the cTrader Platform?
Your feedback is crucial to cTrader's development. Please take a few seconds to share your opinion and help us improve your trading experience. Thanks!
HA

Hansen

Joined 30.01.2023

How to write GetFitness
31 Oct 2023, 08:04


Hi 

I want to save my opt parameters in ctrader, but i can not find the function, so i want to implement it in GetFitness method.

My code is here

    protected override double GetFitness(GetFitnessArgs args)
    {
        var numerator = 1.0;
        numerator = Math.Abs(args.NetProfit * args.NetProfit * args.SharpeRatio * args.SortinoRatio);

        var denominator = 1.0;
        denominator += Math.Abs(args.MaxBalanceDrawdownPercentages * args.MaxEquityDrawdownPercentages);

        /* The 'sign' variable can be either +` or -1 depending on whether
        there are criteria for which their values are less than 0. */
        var sign = numerator * denominator < 0 ? -1 : 1;

        var fitness = sign * numerator / denominator;
        return fitness;
    }

After run opt, i find result is diff from config it in the UI interface.

could you help me?


@Hansen
Replies

PanagiotisChar
01 Nov 2023, 06:38

Hi there,

You are probably translating to English but your issue is not intelligible. I did not understand what your problem is. Can you please rephrase it providing steps how we can reproduce it?

 


@PanagiotisChar

Hansen
01 Nov 2023, 07:16 ( Updated at: 21 Dec 2023, 09:23 )

RE: How to write GetFitness

PanagiotisChar said: 

Hi there,

You are probably translating to English but your issue is not intelligible. I did not understand what your problem is. Can you please rephrase it providing steps how we can reproduce it?

 

I want the code to produce the same results as the interface settings. So could you give me the algo of standand criteria?

in ctrader Steps:

  1. in optimistion function,
  2. select standand creterion
  3. run
  4. get result1

in code:

  1. override getfintness function
  2. in optimistion function,select custom
  3. run
  4. get result2

I find it hard to let result1 as same as result2


@Hansen

PanagiotisCharalampous
01 Nov 2023, 10:37

Hi there,

You won't get the same results if the fitness function is different


@PanagiotisCharalampous

Hansen
02 Nov 2023, 14:00

RE: How to write GetFitness

PanagiotisCharalampous said: 

Hi there,

You won't get the same results if the fitness function is different

Hi Buddy,

You responese make me look like a fool. 

So do you know the algo of fitness function?

Where is the doc?

Can you get the same results as config of ui interface?

I do know how to write fitness function, but accurate algo is not clear… what a pity. 

 


@Hansen

PanagiotisCharalampous
03 Nov 2023, 06:22 ( Updated at: 03 Nov 2023, 06:26 )

RE: RE: How to write GetFitness

Hansen said: 

PanagiotisCharalampous said: 

Hi there,

You won't get the same results if the fitness function is different

Hi Buddy,

You responese make me look like a fool. 

So do you know the algo of fitness function?

Where is the doc?

Can you get the same results as config of ui interface?

I do know how to write fitness function, but accurate algo is not clear… what a pity. 

 

Here is the documentation of the fitness function algorithm

https://help.ctrader.com/ctrader-automate/backtesting-and-optimizing-cbots/#multi-criteria-calculations


@PanagiotisCharalampous

roul.charts
01 Apr 2024, 09:32 ( Updated at: 01 Apr 2024, 17:33 )

Can't stop thinking about the fitness function and how we can produce the best results out of it. I have a hard Stop in the Optimizer mode. So if the Optimizer Szenario breaches my DD parameter, it will immediatelly stop and doesn't waste computing time:


private void MonitorDrawdown()
{
   double currentEquity = Account.Equity;

   // Calculate overall drawdown from the initial balance
   double overallDrawdown = (initialBalance - currentEquity) / initialBalance * 100;

   // Calculate daily drawdown from the previous day's closing balance
   double dailyDrawdown = (previousDayClosingBalance - currentEquity) / previousDayClosingBalance * 100;

   // Overall Drawdown Management
   if (overallDrawdown > MaxOverallLossPercent)
   {
       // Close the single largest losing trade
       var largestLosingTrade = Positions.Where(p => p.SymbolName == Symbol.Name && p.NetProfit < 0)
                                           .OrderBy(p => p.NetProfit)
                                           .FirstOrDefault();
       if (largestLosingTrade != null)
       {
           ClosePosition(largestLosingTrade);
           Print($"Closed trade {largestLosingTrade.Id} to manage drawdown.");
       }

       botStoppedDueToMaxDrawdown = true;
       // Stop the bot: the maximum allowed overall drawdown has been exceeded
       Print($"Drawdown Control: Bot stopped due to overall drawdown! Current: {overallDrawdown}% | Max allowed: {MaxOverallLossPercent}%");

       Stop();
   }

   // Daily Drawdown Management
   else if (dailyDrawdown >= MaxDailyDrawdownPercent && !tradingHaltedToday)
   {
       // Close the single largest losing trade
       var largestLosingTrade = Positions.Where(p => p.SymbolName == Symbol.Name && p.NetProfit < 0)
                                           .OrderBy(p => p.NetProfit)
                                           .FirstOrDefault();
       if (largestLosingTrade != null)
       {
           ClosePosition(largestLosingTrade);
           Print($"Closed trade {largestLosingTrade.Id} to manage drawdown.");
       }

       // After managing trades, recheck drawdown
       dailyDrawdown = (previousDayClosingBalance - currentEquity) / previousDayClosingBalance * 100;
       if (dailyDrawdown >= MaxDailyDrawdownPercent)
       {
           // If still exceeding the limit after closing trades, halt further trading
           tradingHaltedToday = true;
       }
       if (!dailyDrawdownMessagePrinted)
       {
           Print($"Drawdown Control: Trading halted for today! Current: {dailyDrawdown}% | Max allowed: {MaxDailyDrawdownPercent}%");
           dailyDrawdownMessagePrinted = true;
       }
   }
}

So i have a hard stop so i don't want to weigh the Drawdown too much. It's important but not as much as Net Profit and Profit Factor now. The new Manage Drawdown Function will take care about excessive DDs…

There are not many people to discuss about this… seems that most are using other Tools with an Walk forward test possibilities or MT4/5… but i don't like the idea to code modern EAs with old C++ so i try to stick to C# and cTrader. 

Tried a lot now my latest iteration for the Fitness Function is like this:
protected override double GetFitness(GetFitnessArgs args) //It has to be an override - don't change!
{
    // Define weights for each criterion directly affecting their influence
    double netProfitWeight = 0.35;
    double profitFactorWeight = 0.25;
    double drawdownWeight = 0.1;
    double sortinoRatioWeight = 0.1;

    // Filter out undesired strategies
    if (args.ProfitFactor < 1.0) // Ensuring basic profitability
    {
        return 0; // Excludes strategies not meeting basic criteria
    }

    double numerator = (args.NetProfit * netProfitWeight) +
                       (args.ProfitFactor * profitFactorWeight) +
                       (args.SortinoRatio * sortinoRatioWeight);

    double denominator = 1 + (args.MaxEquityDrawdown * drawdownWeight);

    double fitnessScore = numerator / denominator;

    return fitnessScore;
}


@roul.charts