forked from QuantConnect/Lean
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathConstantAlphaModel.cs
More file actions
142 lines (128 loc) · 6 KB
/
ConstantAlphaModel.cs
File metadata and controls
142 lines (128 loc) · 6 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
/*
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
* Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using System;
using System.Collections.Generic;
using QuantConnect.Data;
using QuantConnect.Data.UniverseSelection;
using QuantConnect.Securities;
using static System.FormattableString;
namespace QuantConnect.Algorithm.Framework.Alphas
{
/// <summary>
/// Provides an implementation of <see cref="IAlphaModel"/> that always returns the same insight for each security
/// </summary>
public class ConstantAlphaModel : AlphaModel
{
private readonly InsightType _type;
private readonly InsightDirection _direction;
private readonly TimeSpan _period;
private readonly double? _magnitude;
private readonly double? _confidence;
private readonly double? _weight;
private readonly HashSet<Security> _securities;
private readonly Dictionary<Symbol, DateTime> _insightsTimeBySymbol;
/// <summary>
/// Initializes a new instance of the <see cref="ConstantAlphaModel"/> class
/// </summary>
/// <param name="type">The type of insight</param>
/// <param name="direction">The direction of the insight</param>
/// <param name="period">The period over which the insight with come to fruition</param>
public ConstantAlphaModel(InsightType type, InsightDirection direction, TimeSpan period)
: this(type, direction, period, null, null)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="ConstantAlphaModel"/> class
/// </summary>
/// <param name="type">The type of insight</param>
/// <param name="direction">The direction of the insight</param>
/// <param name="period">The period over which the insight with come to fruition</param>
/// <param name="magnitude">The predicted change in magnitude as a +- percentage</param>
/// <param name="confidence">The confidence in the insight</param>
/// <param name="weight">The portfolio weight of the insights</param>
public ConstantAlphaModel(InsightType type, InsightDirection direction, TimeSpan period, double? magnitude, double? confidence, double? weight = null)
{
_type = type;
_direction = direction;
_period = period;
// Optional
_magnitude = magnitude;
_confidence = confidence;
_weight = weight;
_securities = new HashSet<Security>();
_insightsTimeBySymbol = new Dictionary<Symbol, DateTime>();
Name = $"{nameof(ConstantAlphaModel)}({type},{direction},{period}";
if (magnitude.HasValue)
{
Name += Invariant($",{magnitude.Value}");
}
if (confidence.HasValue)
{
Name += Invariant($",{confidence.Value}");
}
Name += ")";
}
/// <summary>
/// Creates a constant insight for each security as specified via the constructor
/// </summary>
/// <param name="algorithm">The algorithm instance</param>
/// <param name="data">The new data available</param>
/// <returns>The new insights generated</returns>
public override IEnumerable<Insight> Update(QCAlgorithm algorithm, Slice data)
{
foreach (var security in _securities)
{
// security price could be zero until we get the first data point. e.g. this could happen
// when adding both forex and equities, we will first get a forex data point
if (security.Price != 0
&& ShouldEmitInsight(algorithm.UtcTime, security.Symbol))
{
yield return new Insight(security.Symbol, _period, _type, _direction, _magnitude, _confidence, weight: _weight);
}
}
}
/// <summary>
/// Event fired each time the we add/remove securities from the data feed
/// </summary>
/// <param name="algorithm">The algorithm instance that experienced the change in securities</param>
/// <param name="changes">The security additions and removals from the algorithm</param>
public override void OnSecuritiesChanged(QCAlgorithm algorithm, SecurityChanges changes)
{
NotifiedSecurityChanges.UpdateCollection(_securities, changes);
// this will allow the insight to be re-sent when the security re-joins the universe
foreach (var removed in changes.RemovedSecurities)
{
_insightsTimeBySymbol.Remove(removed.Symbol);
}
}
protected virtual bool ShouldEmitInsight(DateTime utcTime, Symbol symbol)
{
DateTime generatedTimeUtc;
if (_insightsTimeBySymbol.TryGetValue(symbol, out generatedTimeUtc))
{
// we previously emitted a insight for this symbol, check it's period to see
// if we should emit another insight
if (utcTime - generatedTimeUtc < _period)
{
return false;
}
}
// we either haven't emitted a insight for this symbol or the previous
// insight's period has expired, so emit a new insight now for this symbol
_insightsTimeBySymbol[symbol] = utcTime;
return true;
}
}
}