public ExperimentResult(Thresholds thresholds, double xirr, int tradeCount, int slipCount)
 {
     Thresholds = thresholds;
     XIrr       = xirr;
     TradeCount = tradeCount;
     SlipCount  = slipCount;
 }
예제 #2
0
        static ExperimentResult RunExperiment(IReadOnlyList <Day> history, Thresholds thresholds, Action <string> logger = null)
        {
            var tradeCount = 0;
            var slipCount  = 0;

            var cash = 0m;
            var depo = new List <decimal>();

            var flowDates  = new List <DateTime>();
            var flowValues = new List <decimal>();

            for (var i = 2; i < history.Count; i++)
            {
                var isLastDay = i == history.Count - 1;
                var day       = history[i];
                var date      = day.Date.ToString("yyyy-MM-dd");
                var price     = day.Close;
                var candidate = new TurnCandidate(history, i - 1);

                if (!isLastDay && candidate.IsDip(thresholds.Low))
                {
                    var buyCount     = 1;
                    var requiredCash = buyCount * price;

                    if (cash < requiredCash)
                    {
                        var topup = requiredCash - cash;
                        flowDates.Add(day.Date);
                        flowValues.Add(topup);
                        cash += topup;
                        logger?.Invoke($"{date} Top-up {topup}");
                    }

                    cash -= requiredCash;
                    depo.AddRange(Enumerable.Repeat(price, buyCount));
                    tradeCount++;

                    logger?.Invoke($"{date} Buy {buyCount} x {price}");
                }

                if (isLastDay || candidate.IsPeak(thresholds.High))
                {
                    if (depo.Any())
                    {
                        var sellCount = depo.Count;

                        var investedValue = depo.Take(sellCount).Sum();
                        var currentValue  = sellCount * price;
                        var earning       = currentValue - investedValue;

                        if (isLastDay || earning > 0)
                        {
                            cash += currentValue;
                            depo.RemoveRange(0, sellCount);
                            tradeCount++;

                            logger?.Invoke($"{date} Sell {sellCount} x {price}, earn {earning}");
                        }
                        else
                        {
                            logger?.Invoke($"{date} Hold");
                        }
                    }
                    else
                    {
                        slipCount++;
                        logger?.Invoke($"{date} Nothing to sell");
                    }
                }
            }

            if (depo.Any())
            {
                throw new Exception();
            }

            var xirr = 0d;

            if (flowValues.Any())
            {
                flowDates.Add(history.Last().Date);
                flowValues.Add(-cash);
                xirr = Excel.FinancialFunctions.Financial.XIrr(flowValues.Select(Convert.ToDouble), flowDates);
            }

            return(new ExperimentResult(thresholds, xirr, tradeCount, slipCount));
        }