The term 'alpha' is used to describe the entire algorithm. Therefore, 'alpha'
produces insights. From this we have things like IAlphaModel, which is the model
defining how insights are produced. We have IAlphaHandler, which defines how the
insights from a single 'alpha' (the algorithm) are managed, analyzed, and stored.
Types closer to the individual prediction level, such as InsightDirection, or
InsightScore relate directly to exactly 1 insight. The distinction between the
two became more clear as we developed the insights API, and from that effort it
was decided to harmonize alpha/insight terminology across the various QC systems.
As we strayed further from the serialization happy path, things started
getting unwieldy quickly. By defining a dedicated DTO to represent the
serialized type, we don't have to much around as much with json.net to
get it to transform/project our type to what we want. The projection is
handled completely within user code and json.net s used to serialize the
simple/flat result object.
This resolves#1623 where we were unable to properly deserialize a
serialized alpha string. The issue was json.net didn't know what
constructor to use. In addition, json.net didn't know it was supposed
to set using the private property setters which isn't default behavior.
When run in an algorithm this time is set by the algorithm. This constructor is added
to make testing alphas a little easier where we can't rely on the algorithm to set the
generated and close times properly.
This change fixes the non-determinism seen in the rolling averaged alpha scores. This was
caused by usage of ConcurrentDictionary coupled with the key being a new guid. The new guid
was the source of non-determinism as it caused the same conceptual alpha from backtest A to
end up in a different 'bucket' on backtest B due to a different guid. The concurrency isn't
actually needed or desirable in this context. The AlphaManager must be invoked synchronously
to avoid inconsistent/non-deterministic analysis. Given this, the collections were changed
to use HashSet<T> and now produces deterministic results independent of the alpha's id.
The IAlphaManagerExtension defines a type that needs to react to events produced
by the AlphaManager. The actual events were removed in favor of a interface to
handle the events. This removes the need to wire events and instead just pass the
extensions to the alph manager and it will handle invoking the extensions at the
appropriate time.
This change removes all charting and statistics aggregation logic from the alpha
handler and moves it into dedicated types, AlphaChartingManagerExtension and
AlphaStatisticsManagerExtension. The resulting types are highly decoupled from the
LEAN ecosystem allowing them to be easily unit tested, whereas before the logic
was embedded in a handler with many many dependencies which would be very hard to
properly unit test.
As part of this change (and in preparation for moving scoring to the alpha thread)
the resolution of SecurityValues was removed from the alpha manager. In this new
pattern, the alpha manager is pushed generated alphas and security values at each
time step.
If we make a prediction for 1 day in the future, we actually mean 1 trading day.
This change updates the alpha analysis logic to take into account the security's
market hours.
It turns out that checking if it's empty is much more expensive than enumerating
an empty collection. This is because IsEmpty acquires all the locks in order to
give a 'snapshot' answer. Enumerating the dictionary directly (not .Keys or .Values)
instead acquires a single finer grained lock at a time. IIRC, one lock will manage a
few buckets internally.
Not seeding this value cause a very heavy 0 starting value to keep the average
suppressed throughout the entire backtest, or until enough alphas are generated
to overcome the initial ema seed value.
Enumerating the values directly requires the dictionary to acquire all global locks
vs enumerating the dictionary's key values pairs uses fine-grained locking at the
bucket level.
Provides estimates of alpha value as well as performs online computations of
alpha scores and other KPIs.
Sends alpha stats to result handler
Update live result with framework flag
Modifies the way we sample charts to be more like the equity sampling that we do.
In this case, we compute a sampling period based off of 1000 samples for the entire
backtest. In live mode, we'll just sample each minute.
A bug in Signal.Clone caused some serious issues for the analysis engine since it thought
every signal was already past it's analysis period.
Added DefaultSignalHandler.OnExit so derived types can clean up before the thread exits.
This commit provides the required infrastructure for analyzing algorithm generated
signals. The analysis of signals is mainly performed via ISignalScoreFunction which
computes scores for a signal. The SignalAnalysisContext provides contextual information
regarding the analysis of a particular signal object and also allows for the storing
of arbitrary state by consumers -- scoring functions can benefit greatly from having
this state tracked (consider any iterative function, or maybe just some heavy calcs to
be persisted between function invocations).
This abstraction point is completely unwarranted. The signal object is really
just a DTO and it's extensible as it is currently defined. This also allows us
to enforce certain behaviors, such as internal set of GeneratedTimeUtc.
Removes GeneratedTimeUtc from the result object as it's now directly on the signal.
Requiring a period here forces signal models to place a time frame on
when their signal is valid. This also allows consumers of signals to
have some expectation of when a prediction should come to fruition.
It's not unreasonable to think users will provide their own ISignal implementation
and we'll want them all behaving by the same serialization rules to make consumption
much easier.
Since these are really just data structures they belon in the common library. Also,
it stands to reason that we'll want to reuse them in other components, such as the
result handler.