17 using System.Collections.Generic;
29 private const double _minimumFinalSplitFactorAllowed = 0.001;
42 public List<MapFileRow>
MapRows {
get;
set; } =
new();
47 public List<CorporateFactorRow>
DividendsSplits {
get;
set; } =
new List<CorporateFactorRow>();
55 private readonly Random _random;
57 private readonly DateTime _delistDate;
58 private readonly
bool _willBeDelisted;
72 _randomValueGenerator = randomValueGenerator;
74 _delistDate = delistDate;
75 _willBeDelisted = willBeDelisted;
76 _symbolGenerator = symbolGenerator;
86 var previousMonth = -1;
87 var monthsTrading = 0;
89 var hasRename = _randomValueGenerator.NextBool(_settings.HasRenamePercentage);
90 var hasSplits = _randomValueGenerator.NextBool(_settings.HasSplitsPercentage);
91 var hasDividends = _randomValueGenerator.NextBool(_settings.HasDividendsPercentage);
92 var dividendEveryQuarter = _randomValueGenerator.NextBool(_settings.DividendEveryQuarterPercentage);
94 var previousX = _random.NextDouble();
104 var months = (int)Math.Round(_settings.End.Subtract(_settings.Start).Days / (365.25 / 12));
105 months = months != 0 ? months : 1;
107 var maxPreviousSplitFactor = 1;
108 var previousSplitFactor = hasSplits ?
GetNextPreviousSplitFactor(_random, minPreviousSplitFactor, maxPreviousSplitFactor) : 1;
109 var previousPriceFactor = hasDividends ? (decimal)Math.Tanh(previousX) : 1;
111 var splitDates =
new List<DateTime>();
112 var dividendDates =
new List<DateTime>();
114 var firstTick =
true;
119 foreach (var tick
in tickHistory)
134 if (splitDates.Count != 0)
136 var deleteDates =
new List<DateTime>();
138 foreach (var splitDate
in splitDates)
140 if (tick.Time > splitDate)
149 deleteDates.Add(splitDate);
154 splitDates.RemoveAll(x => deleteDates.Contains(x));
157 if (dividendDates.Count != 0)
159 var deleteDates =
new List<DateTime>();
161 foreach (var dividendDate
in dividendDates)
163 if (tick.Time > dividendDate)
171 deleteDates.Add(dividendDate);
175 dividendDates.RemoveAll(x => deleteDates.Contains(x));
178 if (tick.Time.Month != previousMonth)
181 if (hasDividends && (tick.Time.Month - 1) % 3 == 0)
184 if (dividendEveryQuarter || _randomValueGenerator.NextBool(10.0))
188 previousX += _random.NextDouble() / 10;
189 previousPriceFactor = (decimal)Math.Tanh(previousX);
190 }
while (previousPriceFactor >= 1.0m || previousPriceFactor <= 0m);
192 dividendDates.Add(_randomValueGenerator.NextDate(tick.Time, tick.Time.AddMonths(1), (DayOfWeek)_random.Next(1, 5)));
196 if (hasSplits && _randomValueGenerator.NextBool(_settings.MonthSplitPercentage))
199 if (_randomValueGenerator.NextBool(5.0))
212 splitDates.Add(_randomValueGenerator.NextDate(tick.Time, tick.Time.AddMonths(1), (DayOfWeek)_random.Next(1, 5)));
215 if (hasRename && _randomValueGenerator.NextBool(10.0))
217 var randomDate = _randomValueGenerator.NextDate(tick.Time, tick.Time.AddMonths(1), (DayOfWeek)_random.Next(1, 5));
220 CurrentSymbol = _symbolGenerator.NextSymbol(_settings.SecurityType, _settings.Market);
223 previousMonth = tick.Time.Month;
227 if (monthsTrading >= 6 && _willBeDelisted && tick.Time > _delistDate)
248 return (decimal)(Math.Pow(_minimumFinalSplitFactorAllowed, 1 / (
double)(2 * months)));
262 return ((decimal)random.NextDouble()) * (upperBound - lowerBound) + lowerBound;