Пример #1
0
        public static void GetAverageDaysPerTrade(this BacktestResult results, GetFitnessArgs args)
        {
            double sum           = 0;
            int    trades        = 0;
            double winSum        = 0;
            int    winningTrades = 0;

            double lossSum      = 0;
            int    losingTrades = 0;

            foreach (var trade in args.History)
            {
                if (double.IsNaN(trade.ClosingPrice))
                {
                    continue;
                }
                sum += (trade.ClosingTime - trade.EntryTime).TotalDays;
                trades++;

                if (trade.NetProfit >= 0)
                {
                    winSum += (trade.ClosingTime - trade.EntryTime).TotalDays;
                    winningTrades++;
                }
                else
                {
                    lossSum += (trade.ClosingTime - trade.EntryTime).TotalDays;
                    losingTrades++;
                }
            }

            results.AverageDaysPerTrade        = sum / trades;
            results.AverageDaysPerWinningTrade = winSum / winningTrades;
            results.AverageDaysPerLosingTrade  = lossSum / losingTrades;
        }
Пример #2
0
        protected virtual void DoLogBacktest(GetFitnessArgs args, BacktestResult backtestResult)
        {
            double   fitness        = backtestResult.Fitness;
            double   initialBalance = backtestResult.InitialBalance;
            TimeSpan timeSpan       = backtestResult.Duration;
            double   aroi           = backtestResult.Aroi;

            if (!double.IsNaN(Template.LogBacktestThreshold) && fitness > Template.LogBacktestThreshold)
            {
                BacktestLogger = this.GetLogger(this.ToString().Replace(' ', '.') + ".Backtest");

                try
                {
                    string resultJson = "";
                    resultJson = Newtonsoft.Json.JsonConvert.SerializeObject(backtestResult);

                    var profit = args.Equity / initialBalance;

                    this.BacktestLogger.LogInformation($"${args.Equity} ({profit.ToString("N1")}x) #{args.History.Count} {args.MaxEquityDrawdownPercentages.ToString("N2")}%dd [from ${initialBalance.ToString("N2")} to ${args.Equity.ToString("N2")}] [fit {fitness.ToString("N1")}] {Environment.NewLine} result = {resultJson} ");
                    var id = Template.Id;


                    backtestResult.GetAverageDaysPerTrade(args);



                    SaveResult(args, backtestResult, fitness, resultJson, id, timeSpan);
                }
                catch (Exception ex)
                {
                    this.BacktestLogger.LogError(ex.ToString());
                    throw;
                }
            }
        }
Пример #3
0
        protected override double GetFitness(GetFitnessArgs args)
        {
            List <bool> constrains = new List <bool>
            {
                args.AverageTrade > 0,
                args.LosingTrades > 0
            };

            if (!constrains.Contains(false))
            {
                List <double> netReturns = new List <double>();

                foreach (HistoricalTrade trade in History)
                {
                    if (trade.Label.StartsWith(RobotId))
                    {
                        netReturns.Add(trade.NetProfit / trade.VolumeInUnits);
                    }
                }

                double geoMeanReturn = Math.Pow(Account.Balance / (Account.Balance - args.NetProfit), 1 / args.TotalTrades) - 1;

                double geostdev     = Math.Sqrt(netReturns.Sum(val => (val - geoMeanReturn) * (val - geoMeanReturn)) / netReturns.Count);
                double geomodSharpe = geoMeanReturn / geostdev;
                double winRatio     = args.WinningTrades / args.TotalTrades;

                return(Math.Log(args.TotalTrades) * winRatio * geomodSharpe);
            }

            else
            {
                return(double.NegativeInfinity);
            }
        }
Пример #4
0
        private async void SaveResult(GetFitnessArgs args, BacktestResult backtestResult, double fitness, string json, string id, TimeSpan timeSpan)
        {
            //var filename = DateTime.Now.ToString("yyyy.MM.dd HH-mm-ss.fff ") + this.GetType().Name + " " + Symbol.Code + " " + id;
            var sym =
#if cAlgo
                MarketSeries.SymbolCode;
#else
                Template.Symbol;
#endif

            var tf =
#if cAlgo
                TimeFrame.ToShortString();
#else
                (this as IHasSingleSeries)?.MarketSeries?.TimeFrame?.Name;
#endif



            var tradesPerMonth = (args.TotalTrades / (timeSpan.TotalDays / 31)).ToString("F1");
            var filename       = fitness.ToString("00.0") + $"ad {tradesPerMonth}tpm {timeSpan.TotalDays.ToString("F0")}d  {backtestResult.AverageDaysPerWinningTrade.ToString("F2")}adwt bot={this.GetType().Name} sym={sym} tf={tf} id={id}";
            var ext            = ".json";
            int i    = 0;
            var dir  = BacktestResultSaveDir;
            var path = Path.Combine(dir, filename + ext);
            if (CreateResultsDirIfMissing && !Directory.Exists(dir))
            {
                Directory.CreateDirectory(dir);
            }
            for (; File.Exists(path); i++, path = Path.Combine(dir, filename + $" ({i})" + ext))
            {
                ;
            }
            using (var sw = new StreamWriter(new FileStream(path, FileMode.Create)))
            {
                await sw.WriteAsync(json).ConfigureAwait(false);
            }
        }
Пример #5
0
        double GetFitness(GetFitnessArgs args)
        {
            try
            {
                var dd = args.MaxEquityDrawdownPercentages;
                dd = Math.Max(FitnessMinDrawdown, dd);

                var initialBalance = args.History.Count == 0 ? args.Equity : args.History[0].Balance - args.History[0].NetProfit;
                if (dd > FitnessMaxDrawdown || args.Equity < initialBalance)
                {
                    return(-dd);
                }

                var botType = this.GetType().FullName;
#if cAlgo
                if (this.GetType().FullName.StartsWith("cAlgo."))
                {
                    botType = this.GetType().GetTypeInfo().BaseType.FullName;
                }
                if (Template.TimeFrame == null)
                {
                    Template.TimeFrame = this.TimeFrame.ToShortString();
                }
                if (Template.Symbol == null)
                {
                    Template.Symbol = this.Symbol.Code;
                }

                if (!StartDate.HasValue || !EndDate.HasValue)
                {
                    throw new ArgumentException("StartDate or EndDate not set.  Are you calling base.OnBar in OnBar?");
                }
#endif
                var backtestResult = new BacktestResult()
                {
                    BacktestDate   = DateTime.UtcNow,
                    BotType        = botType,
                    BotConfigType  = this.Template.GetType().AssemblyQualifiedName,
                    Config         = this.Template,
                    InitialBalance = initialBalance,
                    //Start = this.MarketSeries?.OpenTime?[0],
                    //End = this.MarketSeries?.OpenTime?.LastValue,
                    Start = StartDate.Value,
                    End   = EndDate.Value,

                    AverageTrade = args.AverageTrade,
                    Equity       = args.Equity,
                    //History
                    LosingTrades                  = args.LosingTrades,
                    MaxBalanceDrawdown            = args.MaxBalanceDrawdown,
                    MaxBalanceDrawdownPercentages = args.MaxBalanceDrawdownPercentages,
                    MaxEquityDrawdown             = args.MaxEquityDrawdown,
                    MaxEquityDrawdownPercentages  = args.MaxEquityDrawdownPercentages,
                    NetProfit = args.NetProfit,
                    //PendingOrders
                    //Positions
                    ProfitFactor  = args.ProfitFactor,
                    SharpeRatio   = args.SharpeRatio,
                    SortinoRatio  = args.SortinoRatio,
                    TotalTrades   = args.TotalTrades,
                    WinningTrades = args.WinningTrades,
                };

                double fitness;
                if (!EndDate.HasValue || !StartDate.HasValue)
                {
                    fitness = 0.0;
                }
                else
                {
                    var timeSpan       = EndDate.Value - StartDate.Value;
                    var totalMonths    = timeSpan.TotalDays / 31;
                    var tradesPerMonth = backtestResult.TradesPerMonth;

                    //var aroi = (args.NetProfit / initialBalance) / (timeSpan.TotalDays / 365);
                    var aroi = backtestResult.Aroi;

                    if (args.LosingTrades == 0)
                    {
                        fitness = aroi;
                    }
                    else
                    {
                        fitness = aroi / dd;
                    }

                    var minTrades = Template.BacktestMinTradesPerMonth;

                    //#if cAlgo
                    //                logger.LogInformation($"dd: {args.MaxEquityDrawdownPercentages }  Template.BacktestMinTradesPerMonth {Template.BacktestMinTradesPerMonth} tradesPerMonth {tradesPerMonth}");
                    //#endif

                    if (minTrades > 0 && tradesPerMonth < minTrades && fitness > 0)
                    {
                        fitness *= tradesPerMonth / minTrades;
                    }

                    //#if cAlgo
                    //            Print($"Fitness: {StartDate.Value} - {EndDate.Value} profit: {args.NetProfit} years: {((EndDate.Value - StartDate.Value).TotalDays / 365)} constrained eqDD:{dd} aroi:{aroi} aroi/DD:{aroiVsDD}");
                    //#endif

                    fitness *= 100.0;

                    backtestResult.Fitness = fitness;
                    DoLogBacktest(args, backtestResult);
                }

#if BackTestResult_Debug
                this.BacktestResult = backtestResult;
#endif
                return(fitness);
            }
            catch (Exception ex)
            {
                Logger.LogError("GetFitness threw exception: " + ex);
                throw;
                //return 0;
            }
        }