Skip to content

Commit a7efe5f

Browse files
Merge pull request #1 from QuantConnect/template-vendor-downloader-converter-impl
Create template/skeleton data downloader/converter classes
2 parents 331adf1 + d5ef609 commit a7efe5f

9 files changed

Lines changed: 286 additions & 7 deletions

DataLibrary/DataLibrary.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
<PropertyGroup>
44
<TargetFramework>net5.0</TargetFramework>
5+
<RootNamespace>QuantConnect.DataLibrary</RootNamespace>
56
</PropertyGroup>
67

78
<ItemGroup>

DataLibrary/MyCustomDataType.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222
using QuantConnect.Data;
2323
using System.Collections.Generic;
2424

25-
namespace DataLibrary
25+
namespace QuantConnect.DataLibrary
2626
{
2727
/// <summary>
2828
/// Example custom data type
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
3+
<PropertyGroup>
4+
<OutputType>Exe</OutputType>
5+
<TargetFramework>net5.0</TargetFramework>
6+
<AssemblyName>process</AssemblyName>
7+
</PropertyGroup>
8+
9+
<ItemGroup>
10+
<PackageReference Include="QuantConnect.Common" Version="2.5.11800" />
11+
</ItemGroup>
12+
13+
<ItemGroup>
14+
<ProjectReference Include="..\DataLibrary\DataLibrary.csproj" />
15+
</ItemGroup>
16+
17+
</Project>

DataProcessing/Program.cs

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
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;
17+
using QuantConnect.Configuration;
18+
using QuantConnect.Logging;
19+
using QuantConnect.Util;
20+
21+
namespace QuantConnect.DataProcessing
22+
{
23+
/// <summary>
24+
/// Entrypoint for the data downloader/converter
25+
/// </summary>
26+
public class Program
27+
{
28+
/// <summary>
29+
/// Entrypoint of the program
30+
/// </summary>
31+
/// <returns>Exit code. 0 equals successful, and any other value indicates the downloader/converter failed.</returns>
32+
public static int Main()
33+
{
34+
// Get the configuration values required for your data downloader/converter.
35+
// You will most likely be getting and setting up the values your downloader/converter need here.
36+
var destinationDataFolderDirectory = Config.Get("temp-output-directory", "/temp-output-directory");
37+
var apiKey = Config.Get($"{VendorDataDownloaderConverter.VendorName}-{VendorDataDownloaderConverter.VendorDataName}-api-key", null);
38+
39+
VendorDataDownloaderConverter instance;
40+
try
41+
{
42+
// Pass in the values we got from the configuration into the downloader/converter.
43+
instance = new VendorDataDownloaderConverter(destinationDataFolderDirectory, apiKey);
44+
}
45+
catch (Exception err)
46+
{
47+
Log.Error(err, $"The downloader/converter for {VendorDataDownloaderConverter.VendorDataName} {VendorDataDownloaderConverter.VendorDataName} data failed to be constructed");
48+
return 1;
49+
}
50+
51+
// No need to edit anything below here for most use cases.
52+
// The downloader/converter is ran and cleaned up for you safely here.
53+
try
54+
{
55+
// Run the data downloader/converter.
56+
var success = instance.Run();
57+
if (!success)
58+
{
59+
Log.Error($"QuantConnect.DataProcessing.Program.Main(): Failed to download/process {VendorDataDownloaderConverter.VendorName} {VendorDataDownloaderConverter.VendorDataName} data");
60+
return 1;
61+
}
62+
}
63+
catch (Exception err)
64+
{
65+
Log.Error(err, $"The downloader/converter for {VendorDataDownloaderConverter.VendorDataName} {VendorDataDownloaderConverter.VendorDataName} data exited unexpectedly");
66+
return 1;
67+
}
68+
finally
69+
{
70+
// Run cleanup of the downloader/converter once it has finished or crashed.
71+
instance.DisposeSafely();
72+
}
73+
74+
// The downloader/converter was successful
75+
return 0;
76+
}
77+
}
78+
}
Lines changed: 180 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,180 @@
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.Logging;
17+
using System;
18+
using System.Collections.Generic;
19+
using System.IO;
20+
using System.Linq;
21+
using QuantConnect.DataLibrary;
22+
23+
namespace QuantConnect.DataProcessing
24+
{
25+
/// <summary>
26+
/// Data downloader/converter class example
27+
/// </summary>
28+
public class VendorDataDownloaderConverter : IDisposable
29+
{
30+
/// <summary>
31+
/// Name of the vendor. Only alphanumeric characters, all lowercase and no underscores/spaces.
32+
/// </summary>
33+
public const string VendorName = "gaussgodel";
34+
35+
/// <summary>
36+
/// Type of data that we are downloading/converting. Only alphanumeric characters, all lowercase and no underscores/spaces.
37+
/// </summary>
38+
public const string VendorDataName = "flights";
39+
40+
/// <summary>
41+
/// API key to download data with
42+
/// </summary>
43+
private readonly string _apiKey;
44+
45+
/// <summary>
46+
/// Directory that data will be outputted to
47+
/// </summary>
48+
private readonly string _destinationDirectory;
49+
50+
/// <summary>
51+
/// Has the class been cleaned up yet
52+
/// </summary>
53+
private bool _disposed;
54+
55+
/// <summary>
56+
/// Creates a new instance of the data downloader/converter
57+
/// </summary>
58+
/// <param name="destinationDataFolder">The path to the data folder we want to save data to</param>
59+
/// <param name="apiKey">The API key to download data with</param>
60+
public VendorDataDownloaderConverter(string destinationDataFolder, string apiKey = null)
61+
{
62+
_apiKey = apiKey;
63+
_destinationDirectory = Path.Combine(
64+
destinationDataFolder,
65+
"alternative",
66+
VendorName,
67+
VendorDataName);
68+
69+
// Create the directory ahead of time so that we don't get
70+
// errors when trying to write to this output directory.
71+
Directory.CreateDirectory(_destinationDirectory);
72+
}
73+
74+
/// <summary>
75+
/// Begins running the downloader/converter
76+
/// </summary>
77+
/// <returns>True if downloading/converting was successful, false otherwise</returns>
78+
public bool Run()
79+
{
80+
try
81+
{
82+
// Your data downloading/processing code goes here. The lines below
83+
// can be deleted since they are only meant to be an example.
84+
// ================================================================
85+
var underlying = Symbol.Create("SPY", SecurityType.Equity, Market.USA);
86+
var symbol = Symbol.CreateBase(
87+
typeof(MyCustomDataType),
88+
underlying,
89+
Market.USA);
90+
91+
var lines = new[]
92+
{
93+
"20131001,buy",
94+
"20131003,buy",
95+
"20131006,buy",
96+
"20131007,sell",
97+
"20131009,buy",
98+
"20131011,sell"
99+
};
100+
101+
var instances = lines.Select(x => ParseLine(symbol, x));
102+
var csvLines = instances.Select(x => ToCsvLine(x));
103+
104+
SaveContentsToFile(symbol, csvLines);
105+
}
106+
catch (Exception e)
107+
{
108+
Log.Error(e, $"Failed to download/convert {VendorName} {VendorDataName} data");
109+
return false;
110+
}
111+
112+
return true;
113+
}
114+
115+
/// <summary>
116+
/// Example method to parse and create an instance from a line of CSV
117+
/// </summary>
118+
/// <param name="symbol">Symbol</param>
119+
/// <param name="line">Line of raw data</param>
120+
/// <returns>Instance of <see cref="MyCustomDataType"/></returns>
121+
private MyCustomDataType ParseLine(Symbol symbol, string line)
122+
{
123+
var csv = line.Split(',');
124+
return new MyCustomDataType
125+
{
126+
Time = Parse.DateTimeExact(csv[0], "yyyyMMdd"),
127+
Symbol = symbol,
128+
129+
SomeCustomProperty = csv[1]
130+
};
131+
}
132+
133+
/// <summary>
134+
/// Example method to convert an instance to a CSV line
135+
/// </summary>
136+
/// <param name="instance">Custom Data instance</param>
137+
/// <returns>CSV line</returns>
138+
private string ToCsvLine(MyCustomDataType instance)
139+
{
140+
return string.Join(",",
141+
$"{instance.Time:yyyyMMdd}",
142+
instance.SomeCustomProperty);
143+
}
144+
145+
/// <summary>
146+
/// Example method to save CSV lines to disk
147+
/// </summary>
148+
/// <param name="symbol">Symbol of the data</param>
149+
/// <param name="csvLines">CSV lines to write</param>
150+
private void SaveContentsToFile(Symbol symbol, IEnumerable<string> csvLines)
151+
{
152+
var ticker = symbol.Value.ToLowerInvariant();
153+
154+
var tempPath = new FileInfo(Path.Combine(Path.GetTempPath(), $"{Guid.NewGuid()}-{ticker}.csv"));
155+
var finalPath = Path.Combine(_destinationDirectory, $"{ticker}.csv");
156+
157+
File.WriteAllLines(tempPath.FullName, csvLines);
158+
tempPath.MoveTo(finalPath, true);
159+
}
160+
161+
/// <summary>
162+
/// If you need to shut down things like database connections, threads, or other
163+
/// resources that require manual shutdown, do it here. This will be called after
164+
/// we're done with the <see cref="Run"/> method.
165+
///
166+
/// You don't have to implement this if you don't need to cleanup resources after we're done downloading/processing.
167+
/// </summary>
168+
public void Dispose()
169+
{
170+
if (_disposed)
171+
{
172+
return;
173+
}
174+
175+
// Your cleanup goes here. You don't have to implement it
176+
// if you have nothing that needs to be cleaned up.
177+
_disposed = true;
178+
}
179+
}
180+
}

MyCustomDataType.sln

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DataLibrary", "DataLibrary\
77
EndProject
88
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Tests", "Tests\Tests.csproj", "{46223B6F-6400-4C76-9066-441E8ACB6A21}"
99
EndProject
10+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DataProcessing", "DataProcessing\DataProcessing.csproj", "{9F1E4E69-1D72-4432-93FD-2257EE8FCE0A}"
11+
EndProject
1012
Global
1113
GlobalSection(SolutionConfigurationPlatforms) = preSolution
1214
Debug|Any CPU = Debug|Any CPU
@@ -20,6 +22,10 @@ Global
2022
{46223B6F-6400-4C76-9066-441E8ACB6A21}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
2123
{46223B6F-6400-4C76-9066-441E8ACB6A21}.Release|Any CPU.ActiveCfg = Release|Any CPU
2224
{46223B6F-6400-4C76-9066-441E8ACB6A21}.Release|Any CPU.Build.0 = Release|Any CPU
25+
{9F1E4E69-1D72-4432-93FD-2257EE8FCE0A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
26+
{9F1E4E69-1D72-4432-93FD-2257EE8FCE0A}.Debug|Any CPU.Build.0 = Debug|Any CPU
27+
{9F1E4E69-1D72-4432-93FD-2257EE8FCE0A}.Release|Any CPU.ActiveCfg = Release|Any CPU
28+
{9F1E4E69-1D72-4432-93FD-2257EE8FCE0A}.Release|Any CPU.Build.0 = Release|Any CPU
2329
EndGlobalSection
2430
GlobalSection(SolutionProperties) = preSolution
2531
HideSolutionNode = FALSE

Tests/CustomDataAlgorithm.cs

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,14 +14,12 @@
1414
*
1515
*/
1616

17-
using DataLibrary;
18-
using QuantConnect;
1917
using QuantConnect.Data;
2018
using QuantConnect.Util;
2119
using QuantConnect.Orders;
2220
using QuantConnect.Algorithm;
2321

24-
namespace Tests
22+
namespace QuantConnect.DataLibrary.Tests
2523
{
2624
/// <summary>
2725
/// Example algorithm using the custom data type as a source of alpha

Tests/MyCustomDataTypeTests.cs

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,14 +18,12 @@
1818
using ProtoBuf;
1919
using System.IO;
2020
using System.Linq;
21-
using DataLibrary;
22-
using QuantConnect;
2321
using ProtoBuf.Meta;
2422
using Newtonsoft.Json;
2523
using NUnit.Framework;
2624
using QuantConnect.Data;
2725

28-
namespace Tests
26+
namespace QuantConnect.DataLibrary.Tests
2927
{
3028
[TestFixture]
3129
public class MyCustomDataTypeTests

Tests/Tests.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
<Project Sdk="Microsoft.NET.Sdk">
22
<PropertyGroup>
33
<TargetFramework>net5.0</TargetFramework>
4+
<RootNamespace>QuantConnect.DataLibrary.Tests</RootNamespace>
45
</PropertyGroup>
56
<ItemGroup>
67
<PackageReference Include="protobuf-net" Version="3.0.29" />

0 commit comments

Comments
 (0)