Lean  $LEAN_TAG$
CurrencySubscriptionDataConfigManager.cs
1 /*
2  * QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
3  * Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14 */
15 
16 using System.Collections.Generic;
17 using System.Linq;
19 using QuantConnect.Data;
23 
25 {
26  /// <summary>
27  /// Helper class to keep track of required internal currency <see cref="SubscriptionDataConfig"/>.
28  /// This class is used by the <see cref="UniverseSelection"/>
29  /// </summary>
31  {
32  private readonly HashSet<SubscriptionDataConfig> _toBeAddedCurrencySubscriptionDataConfigs;
33  private readonly HashSet<SubscriptionDataConfig> _addedCurrencySubscriptionDataConfigs;
34  private bool _ensureCurrencyDataFeeds;
35  private bool _pendingSubscriptionDataConfigs;
36  private readonly CashBook _cashBook;
37  private readonly Resolution _defaultResolution;
38  private readonly SecurityManager _securityManager;
39  private readonly SubscriptionManager _subscriptionManager;
40  private readonly ISecurityService _securityService;
41 
42  /// <summary>
43  /// Creates a new instance
44  /// </summary>
45  /// <param name="cashBook">The cash book instance</param>
46  /// <param name="securityManager">The SecurityManager, required by the cash book for creating new securities</param>
47  /// <param name="subscriptionManager">The SubscriptionManager, required by the cash book for creating new subscription data configs</param>
48  /// <param name="securityService">The SecurityService, required by the cash book for creating new securities</param>
49  /// <param name="defaultResolution">The default resolution to use for the internal subscriptions</param>
51  SecurityManager securityManager,
52  SubscriptionManager subscriptionManager,
53  ISecurityService securityService,
54  Resolution defaultResolution)
55  {
56  cashBook.Updated += (sender, args) =>
57  {
58  if (args.UpdateType == CashBookUpdateType.Added)
59  {
60  _ensureCurrencyDataFeeds = true;
61  }
62  };
63 
64  _defaultResolution = defaultResolution;
65  _pendingSubscriptionDataConfigs = false;
66  _securityManager = securityManager;
67  _subscriptionManager = subscriptionManager;
68  _securityService = securityService;
69  _cashBook = cashBook;
70  _addedCurrencySubscriptionDataConfigs = new HashSet<SubscriptionDataConfig>();
71  _toBeAddedCurrencySubscriptionDataConfigs = new HashSet<SubscriptionDataConfig>();
72  }
73 
74  /// <summary>
75  /// Will verify if there are any <see cref="SubscriptionDataConfig"/> to be removed
76  /// for a given added <see cref="Symbol"/>.
77  /// </summary>
78  /// <param name="addedSymbol">The symbol that was added to the data feed system</param>
79  /// <returns>The SubscriptionDataConfig to be removed, null if none</returns>
81  {
82  if (addedSymbol.SecurityType == SecurityType.Crypto
83  || addedSymbol.SecurityType == SecurityType.CryptoFuture
84  || addedSymbol.SecurityType == SecurityType.Forex
85  || addedSymbol.SecurityType == SecurityType.Cfd)
86  {
87  var currencyDataFeed = _addedCurrencySubscriptionDataConfigs
88  .FirstOrDefault(x => x.Symbol == addedSymbol);
89  if (currencyDataFeed != null)
90  {
91  return currencyDataFeed;
92  }
93  }
94  return null;
95  }
96 
97  /// <summary>
98  /// Will update pending currency <see cref="SubscriptionDataConfig"/>
99  /// </summary>
100  /// <returns>True when there are pending currency subscriptions <see cref="GetPendingSubscriptionDataConfigs"/></returns>
102  {
103  if (_ensureCurrencyDataFeeds)
104  {
105  // this allows us to handle the case where SetCash is called when no security has been really added
107  }
108  return _pendingSubscriptionDataConfigs;
109  }
110 
111  /// <summary>
112  /// Will return any pending internal currency <see cref="SubscriptionDataConfig"/> and remove them as pending.
113  /// </summary>
114  /// <returns>Will return the <see cref="SubscriptionDataConfig"/> to be added</returns>
115  public IEnumerable<SubscriptionDataConfig> GetPendingSubscriptionDataConfigs()
116  {
117  var result = new List<SubscriptionDataConfig>();
118  if (_pendingSubscriptionDataConfigs)
119  {
120  foreach (var subscriptionDataConfig in _toBeAddedCurrencySubscriptionDataConfigs)
121  {
122  _addedCurrencySubscriptionDataConfigs.Add(subscriptionDataConfig);
123  result.Add(subscriptionDataConfig);
124  }
125  _toBeAddedCurrencySubscriptionDataConfigs.Clear();
126  _pendingSubscriptionDataConfigs = false;
127  }
128  return result;
129  }
130 
131  /// <summary>
132  /// Checks the current <see cref="SubscriptionDataConfig"/> and adds new necessary currency pair feeds to provide real time conversion data
133  /// </summary>
134  public void EnsureCurrencySubscriptionDataConfigs(SecurityChanges securityChanges, IBrokerageModel brokerageModel)
135  {
136  _ensureCurrencyDataFeeds = false;
137  // remove any 'to be added' if the security has already been added
138  _toBeAddedCurrencySubscriptionDataConfigs.RemoveWhere(
139  config => securityChanges.AddedSecurities.Any(x => x.Symbol == config.Symbol));
140 
141  var newConfigs = _cashBook.EnsureCurrencyDataFeeds(
142  _securityManager,
143  _subscriptionManager,
144  brokerageModel.DefaultMarkets,
145  securityChanges,
146  _securityService,
147  _defaultResolution);
148  foreach (var config in newConfigs)
149  {
150  _toBeAddedCurrencySubscriptionDataConfigs.Add(config);
151  }
152  _pendingSubscriptionDataConfigs = _toBeAddedCurrencySubscriptionDataConfigs.Any();
153  }
154  }
155 }