Skip to content

Commit 4fea612

Browse files
authored
Merge pull request QuantConnect#4390 from gsalaz98/feature-alternative-data-robintrack
Implements Robintrack BaseData and example algorithms
2 parents 17a9047 + d2eb048 commit 4fea612

8 files changed

Lines changed: 390 additions & 0 deletions

File tree

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
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 QuantConnect.Data;
17+
using QuantConnect.Data.Custom.Robintrack;
18+
19+
namespace QuantConnect.Algorithm.CSharp.AltData
20+
{
21+
/// <summary>
22+
/// Looks at users holding the stock AAPL at a given point in time
23+
/// and keeps track of changes in retail investor sentiment.
24+
///
25+
/// We go long if the sentiment increases by 0.5%, and short if it decreases by -0.5%
26+
/// </summary>
27+
public class RobintrackHoldingsAlgorithm : QCAlgorithm
28+
{
29+
private Symbol _aapl;
30+
private Symbol _aaplHoldings;
31+
private decimal _lastValue;
32+
private bool _isLong;
33+
34+
public override void Initialize()
35+
{
36+
SetStartDate(2018, 5, 1);
37+
SetEndDate(2020, 5, 5);
38+
SetCash(100000);
39+
40+
_aapl = AddEquity("AAPL", Resolution.Daily).Symbol;
41+
_aaplHoldings = AddData<RobintrackHoldings>(_aapl).Symbol;
42+
_isLong = false;
43+
}
44+
45+
public override void OnData(Slice data)
46+
{
47+
foreach (var kvp in data.Get<RobintrackHoldings>())
48+
{
49+
var holdings = kvp.Value;
50+
51+
if (_lastValue != 0)
52+
{
53+
var percentChange = (holdings.UsersHolding - _lastValue) / _lastValue;
54+
var holdingInfo = $"There are {holdings.UsersHolding} unique users holding {kvp.Key.Underlying} - users holding % of U.S. equities universe: {holdings.UniverseHoldingPercent * 100m}%";
55+
56+
if (percentChange >= 0.005m && !_isLong)
57+
{
58+
Log($"{UtcTime} - Buying AAPL - {holdingInfo}");
59+
SetHoldings(_aapl, 0.5);
60+
_isLong = true;
61+
}
62+
else if (percentChange <= -0.005m && _isLong)
63+
{
64+
Log($"{UtcTime} - Shorting AAPL - {holdingInfo}");
65+
SetHoldings(_aapl, -0.5);
66+
_isLong = false;
67+
}
68+
}
69+
70+
_lastValue = holdings.UsersHolding;
71+
}
72+
}
73+
}
74+
}

Algorithm.CSharp/QuantConnect.Algorithm.CSharp.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,7 @@
151151
<Compile Include="Alphas\TriangleExchangeRateArbitrageAlpha.cs" />
152152
<Compile Include="Alphas\TripleLeveragedETFPairVolatilityDecayAlpha.cs" />
153153
<Compile Include="Alphas\VixDualThrustAlpha.cs" />
154+
<Compile Include="AltData\RobintrackHoldingsAlgorithm.cs" />
154155
<Compile Include="AltData\CachedAlternativeDataAlgorithm.cs" />
155156
<Compile Include="AltData\BenzingaNewsAlgorithm.cs" />
156157
<Compile Include="AltData\SECReport8KAlgorithm.cs" />
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
# QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
2+
# Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
3+
#
4+
# Licensed under the Apache License, Version 2.0 (the "License");
5+
# you may not use this file except in compliance with the License.
6+
# You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
7+
#
8+
# Unless required by applicable law or agreed to in writing, software
9+
# distributed under the License is distributed on an "AS IS" BASIS,
10+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11+
# See the License for the specific language governing permissions and
12+
# limitations under the License.
13+
14+
from clr import AddReference
15+
AddReference("System")
16+
AddReference("QuantConnect.Algorithm")
17+
AddReference("QuantConnect.Common")
18+
19+
from datetime import datetime, timedelta
20+
21+
from System import *
22+
from QuantConnect import *
23+
from QuantConnect.Algorithm import *
24+
from QuantConnect.Data import *
25+
from QuantConnect.Data.Custom.Robintrack import *
26+
27+
### <summary>
28+
### Looks at users holding the stock AAPL at a given point in time
29+
### and keeps track of changes in retail investor sentiment.
30+
###
31+
### We go long if the sentiment increases by 0.5%, and short if it decreases by -0.5%
32+
### </summary>
33+
class RobintrackHoldingsAlgorithm(QCAlgorithm):
34+
35+
def Initialize(self):
36+
self.lastValue = 0
37+
38+
self.SetStartDate(2018, 5, 1)
39+
self.SetEndDate(2020, 5, 5)
40+
self.SetCash(100000)
41+
42+
self.aapl = self.AddEquity("AAPL", Resolution.Daily).Symbol
43+
self.aaplHoldings = self.AddData(RobintrackHoldings, self.aapl).Symbol
44+
self.isLong = False
45+
46+
def OnData(self, data):
47+
for kvp in data.Get(RobintrackHoldings):
48+
holdings = kvp.Value
49+
50+
if self.lastValue != 0:
51+
percentChange = (holdings.UsersHolding - self.lastValue) / self.lastValue
52+
holdingInfo = f"There are {holdings.UsersHolding} unique users holding {kvp.Key.Underlying} - users holding % of U.S. equities universe: {holdings.UniverseHoldingPercent * 100.0}%"
53+
54+
if percentChange >= 0.005 and not self.isLong:
55+
self.Log(f"{self.UtcTime} - Buying AAPL - {holdingInfo}")
56+
self.SetHoldings(self.aapl, 0.5)
57+
self.isLong = True
58+
59+
elif percentChange <= -0.005 and self.isLong:
60+
self.Log(f"{self.UtcTime} - Shorting AAPL - {holdingInfo}")
61+
self.SetHoldings(self.aapl, -0.5)
62+
self.isLong = False
63+
64+
self.lastValue = holdings.UsersHolding;

Algorithm.Python/QuantConnect.Algorithm.Python.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@
6161
<Content Include="Alphas\ShareClassMeanReversionAlpha.py" />
6262
<Content Include="Alphas\TripleLeverageETFPairVolatilityDecayAlpha.py" />
6363
<Content Include="Alphas\VIXDualThrustAlpha.py" />
64+
<Content Include="AltData\RobintrackHoldingsAlgorithm.py" />
6465
<Content Include="AltData\CachedAlternativeDataAlgorithm.py" />
6566
<Content Include="AltData\BenzingaNewsAlgorithm.py" />
6667
<Content Include="AltData\SECReport8KAlgorithm.py" />
Lines changed: 175 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,175 @@
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 NodaTime;
17+
using System;
18+
using System.Collections.Generic;
19+
using System.Globalization;
20+
using System.IO;
21+
22+
namespace QuantConnect.Data.Custom.Robintrack
23+
{
24+
/// <summary>
25+
/// Aggregate unique user stock holdings
26+
///
27+
/// Data sourced from Robintrack - https://robintrack.net
28+
/// </summary>
29+
public class RobintrackHoldings : BaseData
30+
{
31+
private static List<Resolution> _supportedResolutions = new List<Resolution>
32+
{
33+
Resolution.Second,
34+
Resolution.Minute,
35+
Resolution.Hour,
36+
Resolution.Daily
37+
};
38+
39+
/// <summary>
40+
/// Number of unique users holding a given stock
41+
/// </summary>
42+
public int UsersHolding { get; set; }
43+
44+
/// <summary>
45+
/// Total number of unique holdings across all stocks by users
46+
/// </summary>
47+
public decimal TotalUniqueHoldings { get; set; }
48+
49+
/// <summary>
50+
/// Percentage of the U.S. equities universe that unique users hold stock for
51+
/// </summary>
52+
public decimal UniverseHoldingPercent => UsersHolding / TotalUniqueHoldings;
53+
54+
/// <summary>
55+
/// Alias for <see cref="UsersHolding"/>
56+
/// </summary>
57+
public override decimal Value
58+
{
59+
get { return UsersHolding; }
60+
}
61+
62+
/// <summary>
63+
/// Gets the source of the file
64+
/// </summary>
65+
/// <param name="config">Subscription config</param>
66+
/// <param name="date">Data for the given date to read</param>
67+
/// <param name="isLiveMode">Is live mode</param>
68+
/// <returns>Subscription data source</returns>
69+
public override SubscriptionDataSource GetSource(SubscriptionDataConfig config, DateTime date, bool isLiveMode)
70+
{
71+
if (isLiveMode)
72+
{
73+
throw new NotImplementedException("Live trading currently is not implemented for this data set");
74+
}
75+
76+
return new SubscriptionDataSource(
77+
Path.Combine(
78+
Globals.DataFolder,
79+
"alternative",
80+
"robintrack",
81+
$"{config.Symbol.Underlying.Value.ToLowerInvariant()}.csv"
82+
),
83+
SubscriptionTransportMedium.LocalFile,
84+
FileFormat.Csv
85+
);
86+
}
87+
88+
/// <summary>
89+
/// Reads the data from the source provided in <see cref="GetSource(SubscriptionDataConfig, DateTime, bool)"/>
90+
/// and converts it into an instance of this class (<see cref="RobintrackHoldings"/>).
91+
/// </summary>
92+
/// <param name="config">Subscription config</param>
93+
/// <param name="line">Line to parse</param>
94+
/// <param name="date">Date that the data is being read</param>
95+
/// <param name="isLiveMode">Is live mode</param>
96+
/// <returns>Instance of <see cref="RobintrackHoldings"/> casted as <see cref="BaseData"/></returns>
97+
public override BaseData Reader(SubscriptionDataConfig config, string line, DateTime date, bool isLiveMode)
98+
{
99+
if (isLiveMode)
100+
{
101+
throw new NotImplementedException("Live trading currently is not implemented for this data set");
102+
}
103+
104+
var instance = Read(line);
105+
instance.Symbol = config.Symbol;
106+
107+
return instance;
108+
}
109+
110+
/// <summary>
111+
/// Creates a clone of the current object
112+
/// </summary>
113+
/// <returns>Copy of the current object</returns>
114+
public override BaseData Clone()
115+
{
116+
return new RobintrackHoldings
117+
{
118+
EndTime = EndTime,
119+
Symbol = Symbol,
120+
UsersHolding = UsersHolding,
121+
TotalUniqueHoldings = TotalUniqueHoldings,
122+
};
123+
}
124+
125+
/// <summary>
126+
/// Parses a line of Robintrack data with an optional dateFormat
127+
/// </summary>
128+
/// <param name="line">Line to parse</param>
129+
/// <param name="dateFormat">Date format to parse timestamp in</param>
130+
/// <returns>Instance of this class</returns>
131+
public static RobintrackHoldings Read(string line, string dateFormat = "yyyyMMdd HH:mm:ss")
132+
{
133+
var i = 0;
134+
var csv = line.ToCsvData(size: 3);
135+
var timestamp = Parse.DateTimeExact(csv[i++], dateFormat, DateTimeStyles.AdjustToUniversal);
136+
var usersHolding = Parse.Int(csv[i++]);
137+
var totalUniqueHoldings = Parse.Decimal(csv[i]);
138+
139+
return new RobintrackHoldings
140+
{
141+
EndTime = timestamp,
142+
UsersHolding = usersHolding,
143+
TotalUniqueHoldings = totalUniqueHoldings
144+
};
145+
}
146+
147+
148+
/// <summary>
149+
/// Sets the data timezone
150+
/// </summary>
151+
/// <returns>Timezone</returns>
152+
public override DateTimeZone DataTimeZone()
153+
{
154+
return TimeZones.Utc;
155+
}
156+
157+
/// <summary>
158+
/// Enables mapping of the underlying symbol
159+
/// </summary>
160+
/// <returns>true</returns>
161+
public override bool RequiresMapping()
162+
{
163+
return true;
164+
}
165+
166+
/// <summary>
167+
/// Provides list of supported resolutions
168+
/// </summary>
169+
/// <returns>List of supported resolutions</returns>
170+
public override List<Resolution> SupportedResolutions()
171+
{
172+
return _supportedResolutions;
173+
}
174+
}
175+
}

Common/QuantConnect.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -257,6 +257,7 @@
257257
<Compile Include="Data\Custom\Benzinga\BenzingaNews.cs" />
258258
<Compile Include="Data\Custom\FxcmVolume.cs" />
259259
<Compile Include="Data\Custom\NullData.cs" />
260+
<Compile Include="Data\Custom\Robintrack\RobintrackHoldings.cs" />
260261
<Compile Include="Data\Custom\SEC\ISECReport.cs" />
261262
<Compile Include="Data\Custom\SEC\SECReportBusinessAddress.cs" />
262263
<Compile Include="Data\Custom\SEC\SECReportCompanyData.cs" />

0 commit comments

Comments
 (0)