- Address review improve regression and unit test
- Fix same time scheduled event order
- Adding comments in unit test
- Increasing unit test sleep time
- Only add OnEndOfDay ScheduledEvent if the algorithm implements the
method. Adding unit tests
- Avoid creating a new baseData instance at
`SubscriptionDataSourceReader`
- Adding static `FineFundamental` instance since creating new ones is
expensive
- Set `CanRunLocally => false` for training regression algorithms
- Reverting sorting changes at `BacktestingRealTimeHandler` due to
performance degradation of current scheduled event benchmark algorithm
Per review comments provided in #3743 regarding the
training/long-running scheduled events and the leaky
bucket algorithm. See the PR for more information.
In order to continue to provide debugging support in the QC cloud, the
scheduled events were moved from inside of a task to the algorithm's
main execution thread. This necesitated a different methodology for
managing timeouts. Instead of raising an exception when attempting to
request additional time when none is remaining, we're now simply allowing
the isolator's limit to be reached by virtue of not incrementing the
additional minutes in the time manager. This uncovered a bug in LEAN
engine where if the isolator terminates an algorithm, then the status
of the algorithm (on the algorithm manager instance) isn't properly
updated to indicate RuntimeError. This is in direct conflict with the
status update that is provided to the api, which is RuntimeError, so
this change remedies that issue as well. One of the regression algorithms
depends on this status value being properly flipped to RuntimeError in
the event that the isolator limit is reached.
See #3319
We restrict each algorithm time loop to a pre-determined amount of time.
Exceeding this limit will cause the algorithm to immediately terminate.
This quickly becomes an issue when considering users running trainable
models that have a long initialization period that exceeds the time loop
maximum.
This change provides a mechanism through which a long-running scheduled
event is permitted to keep running and is permitted to avoid the time loop
permitted by requesting additional time. Requests for additional time are
limited according to a leaky bucket implementation whose parameters are
set via the job's controls structure. The fundamental time unit for the
algorithm is a single minute.
Here's how it works. If a scheduled event takes longer than one full wall
clock second then a request is made to the leaky bucket for one more minute.
If the scheduled event continues to take more time, it will continue to
request additional minutes. Each requested minute will prevent the algorithm's
time loop check from terminating the algorithm. When the bucket is empty and
no more minutes are available to be requested, a TimeoutException is thrown
causing a cascade that ends in the algorithm's termination and status being
flipped to RuntimeError.
Additionally, this applies equally to ALL scheduled events. While some helpers
were added with the naming of Train and TrainNow to the ScheduleManager, these
methods don't do anything special and the infrastructure doesn't otherwise
flag them as different, so this feature becomes part of the core Scheduled
Event feature set.
Further, the live scheduled events were not touched and are still pending
further discussion regarding the value added by enforcing a time restriction
when simulation time and wall clock time are equivalent.
Fixes#3319
- Adding `IRealTimeHandler.OnSecurityChanged()` will be used to update
the `OnEndOfDay` security related scheduled events
- Adding `BaseRealTimeHandler.cs` to reduce code duplication in the
`Backtesting` and `LiveTrading` `RealTimeHandlers`
- Adding CSharp and Python regression tests
- Deprecating `OnEndOfDay()` callback because of two reasons, mainly
because Python does not support two methods with the same name, but also
because different assets have different market close times.
- `ScheduledEvents` set at the same time will now be deterministic
When a `ScheduledEventException` was thrown, `IAlgorithm.RunTimeError` was not set as `ScheduledEventException` , but as `Exception` with the orginal exception message and no inner exception.
Without the inner exception, information on the user exception is lost. In python algorithm, the stack trace is completely lost.
Removes ScheduledEventExceptionMessage property as it is redundant to Message property inherited from parent class.
This PR is an attempt to reduce contention in concurrent dictionaries, replacing method calls using full locks with lock-free equivalents:
- dictionary.Count -> dictionary.Skip(0).Count()
- dictionary.Keys -> dictionary.Select(x => x.Key)
- dictionary.Values -> dictionary.Select(x => x.Value)
The most frequent usages of these methods are: CashBook, SecurityManager, UniverseManager and indirectly, SecurityPortfolioManager.
The reasons for this update are explained very clearly in this article:
https://arbel.net/2013/02/03/best-practices-for-using-concurrentdictionary/
Catching the exception in BacktestingRealTimeHandler prevents unhandled errors in backtesting and provides more specific logging to make debugging easier for users
These changes fix a bug so that when an exception is thrown with the LiveTradingResultHandler, the error is handled and the next scheduled event can happen as scheduled.
If backtesting, we need to check if there are realtime events in the past
which didn't fire because at the scheduled times there was no data (i.e. markets closed) and fire them with the correct date/time.
In live mode, no changes are needed.
Many places in the code used Log.Error(err.Message) or equivalent which
strips out all the really useful information, such as the stack trace
and inner exceptions. Using Log.Error(exception) is the correct way to
log an error as it will correctly write all the message details, also,
by passing the full Exception object we can improve the logging in this
one place and all call sites will automatically benefit from the improvements
This includes updating all usages of symbol as a security identifier to use the new type.
The type includes a unique field, SID, as well as the current ticker's value. This allows
for consistent addressability while also allowing the ticker to evolve over time with the
mapping changes.
Effort was made to maintain compile and runtime backwards compatibility.
Adds the ScheduleManager which allows an algorithm to add/remove scheduled events
Check out the ScheduledEventsAlgorithm for syntax
ScheduledEvents are at their core an IEnumerator<DateTime> that defines the event times coupled with a callback
IDateRule defines dates for events
ITimeRule defines time(s) on a given date for events
Adds concept of Subscription to contain everything a data feed needs in order to process single data feed item
Moves preparation of all data to data feed thread, algo thread receives data in format it needs
QCAlgorithm.SetUniverse( func ) allows selection based on market/symbol/dollar volume/price
Remove laziness from Slice as optimization, no order by in real time handler
In some cases we need to exit the applications, in others we just want to log.
For instance, if the transaction handler throws an unexpected exception then we
can't be confident in the state of our orders but if the live result handler fails,
the algo is still OK and consistent state, we just may not receive a packet for that time step