diff --git a/.github/issue_template.md b/.github/issue_template.md new file mode 100644 index 0000000..c50f3e3 --- /dev/null +++ b/.github/issue_template.md @@ -0,0 +1,27 @@ + + +#### Expected Behavior + + +#### Actual Behavior + + +#### Potential Solution + + +#### Reproducing the Problem + + +#### System Information + + +#### Checklist + + +- [ ] I have completely filled out this template +- [ ] I have confirmed that this issue exists on the current `master` branch +- [ ] I have confirmed that this is not a duplicate issue by searching [issues](https://github.com/QuantConnect/Lean/issues) + +- [ ] I have provided detailed steps to reproduce the issue + + \ No newline at end of file diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md new file mode 100644 index 0000000..1418a96 --- /dev/null +++ b/.github/pull_request_template.md @@ -0,0 +1,42 @@ + + + +#### Description + + +#### Related Issue + + + + + +#### Motivation and Context + + +#### Requires Documentation Change + + +#### How Has This Been Tested? + + + + +#### Types of changes + +- [ ] Bug fix (non-breaking change which fixes an issue) +- [ ] Refactor (non-breaking change which improves implementation) +- [ ] Performance (non-breaking change which improves performance. Please add associated performance test and results) +- [ ] New feature (non-breaking change which adds functionality) +- [ ] Breaking change (fix or feature that would cause existing functionality to change) +- [ ] Non-functional change (xml comments/documentation/etc) + +#### Checklist: + + +- [ ] My code follows the code style of this project. +- [ ] I have read the **CONTRIBUTING** [document](https://github.com/QuantConnect/Lean/blob/master/CONTRIBUTING.md). +- [ ] I have added tests to cover my changes. +- [ ] All new and existing tests passed. +- [ ] My branch follows the naming convention `bug--` or `feature--` + + diff --git a/.github/workflows/gh-actions.yml b/.github/workflows/gh-actions.yml new file mode 100644 index 0000000..f24179d --- /dev/null +++ b/.github/workflows/gh-actions.yml @@ -0,0 +1,47 @@ +name: Build & Test + +on: + push: + branches: ['*'] + +jobs: + build: + runs-on: ubuntu-20.04 + env: + QC_TEMPLATE_BROKERAGE_KEY: ${{ secrets.QC_TEMPLATE_BROKERAGE_KEY }} + QC_TEMPLATE_BROKERAGE_SECRET: ${{ secrets.QC_TEMPLATE_BROKERAGE_SECRET }} + steps: + - name: Checkout + uses: actions/checkout@v2 + - name: Free space + run: df -h && rm -rf /opt/hostedtoolcache* && df -h + + - uses: addnab/docker-run-action@v3 + with: + image: quantconnect/lean:foundation + options: --workdir /__w/Lean.Brokerages.Template/Lean.Brokerages.Template -v /home/runner/work:/__w -e QC_TEMPLATE_BROKERAGE_KEY=${{ secrets.QC_TEMPLATE_BROKERAGE_KEY }} -e QC_TEMPLATE_BROKERAGE_SECRET=${{ secrets.QC_TEMPLATE_BROKERAGE_SECRET }} -e QC_JOB_USER_ID=${{ secrets.QC_JOB_USER_ID }} -e QC_API_ACCESS_TOKEN=${{ secrets.QC_API_ACCESS_TOKEN }} -e QC_JOB_ORGANIZATION_ID=${{ secrets.QC_JOB_ORGANIZATION_ID }} + + - name: Checkout Lean Same Branch + id: lean-same-branch + uses: actions/checkout@v2 + continue-on-error: true + with: + ref: ${{ github.ref }} + repository: QuantConnect/Lean + path: Lean + + - name: Checkout Lean Master + if: steps.lean-same-branch.outcome != 'success' + uses: actions/checkout@v2 + with: + repository: QuantConnect/Lean + path: Lean + + - name: Move Lean + run: mv Lean ../Lean + + - name: Build + run: dotnet build /p:Configuration=Release /v:quiet /p:WarningLevel=1 QuantConnect.TemplateBrokerage.sln + + - name: Run Tests + run: dotnet test ./QuantConnect.TemplateBrokerage.Tests/bin/Release/QuantConnect.Brokerages.Template.Tests.dll diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..866dd07 --- /dev/null +++ b/.gitignore @@ -0,0 +1,279 @@ +# Object files +*.o +*.ko +*.obj +*.elf +*.pyc + +# Visual Studio Project Items: +*.suo + +# Precompiled Headers +*.gch +*.pch + +# Libraries +*.lib +*.a +*.la +*.lo + +# Shared objects (inc. Windows DLLs) +#*.dll +*.so +*.so.* +*.dylib + +# Executables +*/bin/*.exe +*.out +*.app +*.i*86 +*.x86_64 +*.hex + +# QC Cloud Setup Bash Files +*.sh +# Include docker launch scripts for Mac/Linux +!run_docker.sh +!research/run_docker_notebook.sh + +# QC Config Files: +# config.json + +# QC-C-Specific +*Engine/bin/Debug/cache/data/*.zip +*/obj/* +*/bin/* +*Data/* +*Docker/* +*/Docker/* +*Algorithm.Python/Lib/* +*/[Ee]xtensions/* +!**/Libraries/* + +# C Debug Binaries +*.pdb + +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. + +# User-specific files +*.suo +*.user +*.userosscache +*.sln.docstates +*.userprefs + +# Build results +[Dd]ebug/ +[Dd]ebugPublic/ +[Rr]elease/ +[Rr]eleases/ +x64/ +x86/ +.vs/ +build/ +bld/ +[Bb]in/ +[Oo]bj/ + +# Roslyn cache directories +*.ide/ + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +#NUNIT +*.VisualState.xml +TestResult.xml + +# Build Results of an ATL Project +[Dd]ebugPS/ +[Rr]eleasePS/ +dlldata.c + +*_i.c +*_p.c +*_i.h +*.ilk +*.meta +*.obj +*.pch +*.pdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*.log +*.vspscc +*.vssscc +.builds +*.pidb +*.svclog +*.scc + +# Chutzpah Test files +_Chutzpah* + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opensdf +*.sdf +*.cachefile + +# Visual Studio profiler +*.psess +*.vsp +*.vspx + +# TFS 2012 Local Workspace +$tf/ + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper*/ +*.[Rr]e[Ss]harper +*.DotSettings +*.DotSettings.user + +# JustCode is a .NET coding addin-in +.JustCode + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# NCrunch +_NCrunch_* +.*crunch*.local.xml + +# MightyMoose +*.mm.* +AutoTest.Net/ + +# Web workbench (sass) +.sass-cache/ + +# Installshield output folder +[Ee]xpress/ + +# JetBrains Rider +.idea/ + +# DocProject is a documentation generator add-in +DocProject/buildhelp/ +DocProject/Help/*.HxT +DocProject/Help/*.HxC +DocProject/Help/*.hhc +DocProject/Help/*.hhk +DocProject/Help/*.hhp +DocProject/Help/Html2 +DocProject/Help/html + +# Click-Once directory +publish/ + +# Publish Web Output +*.[Pp]ublish.xml +*.azurePubxml +# TODO: Comment the next line if you want to checkin your web deploy settings +# but database connection strings (with potential passwords) will be unencrypted +*.pubxml +*.publishproj + +# NuGet Packages +*.nupkg +!LocalPackages/* +# The packages folder can be ignored because of Package Restore +**/packages/* +# except build/, which is used as an MSBuild target. +!**/packages/build/ +# If using the old MSBuild-Integrated Package Restore, uncomment this: +#!**/packages/repositories.config +# ignore sln level nuget +.nuget/ +!.nuget/NuGet.config + +# Windows Azure Build Output +csx/ +*.build.csdef + +# Windows Store app package directory +AppPackages/ + +# Others +*.Cache +ClientBin/ +[Ss]tyle[Cc]op.* +~$* +*~ +*.dbmdl +*.dbproj.schemaview +*.pfx +*.publishsettings +node_modules/ +bower_components/ + +# RIA/Silverlight projects +Generated_Code/ + +# Backup & report files from converting an old project file +# to a newer Visual Studio version. Backup files are not needed, +# because we have git ;-) +_UpgradeReport_Files/ +Backup*/ +UpgradeLog*.XML +UpgradeLog*.htm + +# SQL Server files +*.mdf +*.ldf + +# Business Intelligence projects +*.rdl.data +*.bim.layout +*.bim_*.settings + +# Microsoft Fakes +FakesAssemblies/ + +# Test Runner +testrunner/ + +# Meld original diff files +*.orig + +# Output chart data +Charts/ + +# NCrunch files +*.ncrunchsolution +*.ncrunchproject + +# QuantConnect plugin files +QuantConnectProjects.xml +Launcher/Plugins/* +/ApiPython/dist +/ApiPython/quantconnect.egg-info +/ApiPython/quantconnect.egg-info/* + +QuantConnect.Lean.sln.DotSettings* + +#User notebook files +Research/Notebooks + +#Docker result files +Results/ \ No newline at end of file diff --git a/QuantConnect.TemplateBrokerage.Tests/QuantConnect.TemplateBrokerage.Tests.csproj b/QuantConnect.TemplateBrokerage.Tests/QuantConnect.TemplateBrokerage.Tests.csproj new file mode 100644 index 0000000..e5e77ac --- /dev/null +++ b/QuantConnect.TemplateBrokerage.Tests/QuantConnect.TemplateBrokerage.Tests.csproj @@ -0,0 +1,41 @@ + + + + Release + AnyCPU + net6.0 + + false + Copyright © 2021 + UnitTest + bin\$(Configuration)\ + QuantConnect.Brokerages.Template.Tests + QuantConnect.Brokerages.Template.Tests + QuantConnect.Brokerages.Template.Tests + QuantConnect.Brokerages.Template.Tests + false + + + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + + + + + + + + + + PreserveNewest + + + diff --git a/QuantConnect.TemplateBrokerage.Tests/TemplateBrokerageAdditionalTests.cs b/QuantConnect.TemplateBrokerage.Tests/TemplateBrokerageAdditionalTests.cs new file mode 100644 index 0000000..e321551 --- /dev/null +++ b/QuantConnect.TemplateBrokerage.Tests/TemplateBrokerageAdditionalTests.cs @@ -0,0 +1,32 @@ +/* + * 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 NUnit.Framework; +using QuantConnect.Util; +using QuantConnect.Interfaces; + +namespace QuantConnect.Brokerages.Template.Tests +{ + [TestFixture] + public class TemplateBrokerageAdditionalTests + { + [Test] + public void ParameterlessConstructorComposerUsage() + { + var brokerage = Composer.Instance.GetExportedValueByTypeName("TemplateBrokerage"); + Assert.IsNotNull(brokerage); + } + } +} \ No newline at end of file diff --git a/QuantConnect.TemplateBrokerage.Tests/TemplateBrokerageDataQueueHandlerTests.cs b/QuantConnect.TemplateBrokerage.Tests/TemplateBrokerageDataQueueHandlerTests.cs new file mode 100644 index 0000000..b552c73 --- /dev/null +++ b/QuantConnect.TemplateBrokerage.Tests/TemplateBrokerageDataQueueHandlerTests.cs @@ -0,0 +1,81 @@ +/* + * 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 NUnit.Framework; +using System.Threading; +using QuantConnect.Data; +using QuantConnect.Tests; +using QuantConnect.Logging; +using QuantConnect.Data.Market; + +namespace QuantConnect.Brokerages.Template.Tests +{ + [TestFixture] + public partial class TemplateBrokerageTests + { + private static TestCaseData[] TestParameters + { + get + { + return new[] + { + // valid parameters, for example + new TestCaseData(Symbols.BTCUSD, Resolution.Tick, false), + new TestCaseData(Symbols.BTCUSD, Resolution.Minute, false), + new TestCaseData(Symbols.BTCUSD, Resolution.Second, false), + }; + } + } + + [Test, TestCaseSource(nameof(TestParameters))] + public void StreamsData(Symbol symbol, Resolution resolution, bool throwsException) + { + var cancelationToken = new CancellationTokenSource(); + var brokerage = (TemplateBrokerage)Brokerage; + + SubscriptionDataConfig[] configs; + if (resolution == Resolution.Tick) + { + var tradeConfig = new SubscriptionDataConfig(GetSubscriptionDataConfig(symbol, resolution), tickType: TickType.Trade); + var quoteConfig = new SubscriptionDataConfig(GetSubscriptionDataConfig(symbol, resolution), tickType: TickType.Quote); + configs = new[] { tradeConfig, quoteConfig }; + } + else + { + configs = new[] { GetSubscriptionDataConfig(symbol, resolution), + GetSubscriptionDataConfig(symbol, resolution) }; + } + + foreach (var config in configs) + { + ProcessFeed(brokerage.Subscribe(config, (s, e) => { }), + cancelationToken, + (baseData) => { if (baseData != null) { Log.Trace($"{baseData}"); } + }); + } + + Thread.Sleep(20000); + + foreach (var config in configs) + { + brokerage.Unsubscribe(config); + } + + Thread.Sleep(20000); + + cancelationToken.Cancel(); + } + } +} diff --git a/QuantConnect.TemplateBrokerage.Tests/TemplateBrokerageFactoryTests.cs b/QuantConnect.TemplateBrokerage.Tests/TemplateBrokerageFactoryTests.cs new file mode 100644 index 0000000..c3f90ec --- /dev/null +++ b/QuantConnect.TemplateBrokerage.Tests/TemplateBrokerageFactoryTests.cs @@ -0,0 +1,32 @@ +/* + * 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 NUnit.Framework; +using QuantConnect.Interfaces; +using QuantConnect.Util; + +namespace QuantConnect.Brokerages.Template.Tests +{ + [TestFixture, Ignore("This test requires a configured TemplateBrokerageFactory")] + public class TemplateBrokerageFactoryTests + { + [Test] + public void InitializesFactoryFromComposer() + { + using var factory = Composer.Instance.Single(instance => instance.BrokerageType == typeof(TemplateBrokerage)); + Assert.IsNotNull(factory); + } + } +} \ No newline at end of file diff --git a/QuantConnect.TemplateBrokerage.Tests/TemplateBrokerageHistoryProviderTests.cs b/QuantConnect.TemplateBrokerage.Tests/TemplateBrokerageHistoryProviderTests.cs new file mode 100644 index 0000000..3ec17cd --- /dev/null +++ b/QuantConnect.TemplateBrokerage.Tests/TemplateBrokerageHistoryProviderTests.cs @@ -0,0 +1,132 @@ +/* + * 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.Linq; +using NUnit.Framework; +using QuantConnect.Data; +using QuantConnect.Tests; +using QuantConnect.Logging; +using QuantConnect.Securities; +using QuantConnect.Data.Market; +using QuantConnect.Lean.Engine.HistoricalData; + +namespace QuantConnect.Brokerages.Template.Tests +{ + [TestFixture, Ignore("Not implemented")] + public class TemplateBrokerageHistoryProviderTests + { + private static TestCaseData[] TestParameters + { + get + { + return new[] + { + // valid parameters, example: + new TestCaseData(Symbols.BTCUSD, Resolution.Tick, TimeSpan.FromMinutes(1), TickType.Quote, typeof(Tick), false), + new TestCaseData(Symbols.BTCUSD, Resolution.Minute, TimeSpan.FromMinutes(10), TickType.Quote, typeof(QuoteBar), false), + new TestCaseData(Symbols.BTCUSD, Resolution.Daily, TimeSpan.FromDays(10), TickType.Quote, typeof(QuoteBar), false), + + new TestCaseData(Symbols.BTCUSD, Resolution.Tick, TimeSpan.FromMinutes(1), TickType.Trade, typeof(Tick), false), + new TestCaseData(Symbols.BTCUSD, Resolution.Minute, TimeSpan.FromMinutes(10), TickType.Trade, typeof(TradeBar), false), + new TestCaseData(Symbols.BTCUSD, Resolution.Daily, TimeSpan.FromDays(10), TickType.Trade, typeof(TradeBar), false), + + // invalid parameter, validate SecurityType more accurate + new TestCaseData(Symbols.SPY, Resolution.Hour, TimeSpan.FromHours(14), TickType.Quote, typeof(QuoteBar), true), + + /// New Listed Symbol on Brokerage + new TestCaseData(Symbol.Create("SUSHIGBP", SecurityType.Crypto, Market.Coinbase), Resolution.Minute, TimeSpan.FromHours(2), TickType.Trade, typeof(TradeBar), false), + + /// Symbol was delisted form Brokerage (can return history data or not) + new TestCaseData(Symbol.Create("SNTUSD", SecurityType.Crypto, Market.Coinbase), Resolution.Daily, TimeSpan.FromDays(14), TickType.Trade, typeof(TradeBar), true), + }; + } + } + + [Test, TestCaseSource(nameof(TestParameters))] + public void GetsHistory(Symbol symbol, Resolution resolution, TimeSpan period, TickType tickType, Type dataType, bool throwsException) + { + TestDelegate test = () => + { + var brokerage = new TemplateBrokerage(null); + + var historyProvider = new BrokerageHistoryProvider(); + historyProvider.SetBrokerage(brokerage); + historyProvider.Initialize(new HistoryProviderInitializeParameters(null, null, null, + null, null, null, null, + false, null, null)); + + var marketHoursDatabase = MarketHoursDatabase.FromDataFolder(); + var now = DateTime.UtcNow; + var requests = new[] + { + new HistoryRequest(now.Add(-period), + now, + dataType, + symbol, + resolution, + marketHoursDatabase.GetExchangeHours(symbol.ID.Market, symbol, symbol.SecurityType), + marketHoursDatabase.GetDataTimeZone(symbol.ID.Market, symbol, symbol.SecurityType), + resolution, + false, + false, + DataNormalizationMode.Adjusted, + tickType) + }; + + var historyArray = historyProvider.GetHistory(requests, TimeZones.Utc).ToArray(); + foreach (var slice in historyArray) + { + if (resolution == Resolution.Tick) + { + foreach (var tick in slice.Ticks[symbol]) + { + Log.Debug($"{tick}"); + } + } + else if (slice.QuoteBars.TryGetValue(symbol, out var quoteBar)) + { + Log.Debug($"{quoteBar}"); + } + else if (slice.Bars.TryGetValue(symbol, out var tradeBar)) + { + Log.Debug($"{tradeBar}"); + } + } + + if (historyProvider.DataPointCount > 0) + { + // Ordered by time + Assert.That(historyArray, Is.Ordered.By("Time")); + + // No repeating bars + var timesArray = historyArray.Select(x => x.Time).ToArray(); + Assert.AreEqual(timesArray.Length, timesArray.Distinct().Count()); + } + + Log.Trace("Data points retrieved: " + historyProvider.DataPointCount); + }; + + if (throwsException) + { + Assert.Throws(test); + } + else + { + Assert.DoesNotThrow(test); + } + } + } +} diff --git a/QuantConnect.TemplateBrokerage.Tests/TemplateBrokerageSymbolMapperTests.cs b/QuantConnect.TemplateBrokerage.Tests/TemplateBrokerageSymbolMapperTests.cs new file mode 100644 index 0000000..d3574d8 --- /dev/null +++ b/QuantConnect.TemplateBrokerage.Tests/TemplateBrokerageSymbolMapperTests.cs @@ -0,0 +1,35 @@ +/* + * 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 NUnit.Framework; + +namespace QuantConnect.Brokerages.Template.Tests +{ + [TestFixture, Ignore("Not implemented")] + public class TemplateBrokerageSymbolMapperTests + { + [Test] + public void ReturnsCorrectLeanSymbol() + { + + } + + [Test] + public void ReturnsCorrectBrokerageSymbol() + { + + } + } +} \ No newline at end of file diff --git a/QuantConnect.TemplateBrokerage.Tests/TemplateBrokerageTests.cs b/QuantConnect.TemplateBrokerage.Tests/TemplateBrokerageTests.cs new file mode 100644 index 0000000..d163aba --- /dev/null +++ b/QuantConnect.TemplateBrokerage.Tests/TemplateBrokerageTests.cs @@ -0,0 +1,102 @@ +/* + * 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 NUnit.Framework; +using QuantConnect.Tests; +using QuantConnect.Interfaces; +using QuantConnect.Securities; +using QuantConnect.Tests.Brokerages; + +namespace QuantConnect.Brokerages.Template.Tests +{ + [TestFixture, Ignore("Not implemented")] + public partial class TemplateBrokerageTests : BrokerageTests + { + protected override Symbol Symbol { get; } + protected override SecurityType SecurityType { get; } + + protected override IBrokerage CreateBrokerage(IOrderProvider orderProvider, ISecurityProvider securityProvider) + { + throw new System.NotImplementedException(); + } + protected override bool IsAsync() + { + throw new System.NotImplementedException(); + } + + protected override decimal GetAskPrice(Symbol symbol) + { + throw new System.NotImplementedException(); + } + + + /// + /// Provides the data required to test each order type in various cases + /// + private static TestCaseData[] OrderParameters() + { + return new[] + { + new TestCaseData(new MarketOrderTestParameters(Symbols.BTCUSD)).SetName("MarketOrder"), + new TestCaseData(new LimitOrderTestParameters(Symbols.BTCUSD, 10000m, 0.01m)).SetName("LimitOrder"), + new TestCaseData(new StopMarketOrderTestParameters(Symbols.BTCUSD, 10000m, 0.01m)).SetName("StopMarketOrder"), + new TestCaseData(new StopLimitOrderTestParameters(Symbols.BTCUSD, 10000m, 0.01m)).SetName("StopLimitOrder"), + new TestCaseData(new LimitIfTouchedOrderTestParameters(Symbols.BTCUSD, 10000m, 0.01m)).SetName("LimitIfTouchedOrder") + }; + } + + [Test, TestCaseSource(nameof(OrderParameters))] + public override void CancelOrders(OrderTestParameters parameters) + { + base.CancelOrders(parameters); + } + + [Test, TestCaseSource(nameof(OrderParameters))] + public override void LongFromZero(OrderTestParameters parameters) + { + base.LongFromZero(parameters); + } + + [Test, TestCaseSource(nameof(OrderParameters))] + public override void CloseFromLong(OrderTestParameters parameters) + { + base.CloseFromLong(parameters); + } + + [Test, TestCaseSource(nameof(OrderParameters))] + public override void ShortFromZero(OrderTestParameters parameters) + { + base.ShortFromZero(parameters); + } + + [Test, TestCaseSource(nameof(OrderParameters))] + public override void CloseFromShort(OrderTestParameters parameters) + { + base.CloseFromShort(parameters); + } + + [Test, TestCaseSource(nameof(OrderParameters))] + public override void ShortFromLong(OrderTestParameters parameters) + { + base.ShortFromLong(parameters); + } + + [Test, TestCaseSource(nameof(OrderParameters))] + public override void LongFromShort(OrderTestParameters parameters) + { + base.LongFromShort(parameters); + } + } +} \ No newline at end of file diff --git a/QuantConnect.TemplateBrokerage.Tests/TemplateExchangeInfoDownloaderTests.cs b/QuantConnect.TemplateBrokerage.Tests/TemplateExchangeInfoDownloaderTests.cs new file mode 100644 index 0000000..cec756a --- /dev/null +++ b/QuantConnect.TemplateBrokerage.Tests/TemplateExchangeInfoDownloaderTests.cs @@ -0,0 +1,46 @@ +/* + * 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 NUnit.Framework; +using QuantConnect.ToolBox; +using QuantConnect.Util; +using System; +using System.Linq; + +namespace QuantConnect.Brokerages.Template.Tests +{ + [TestFixture, Ignore("This test requires a configured TemplateExchangeInfoDownloader")] + public class TemplateExchangeInfoDownloaderTests + { + [Test] + public void GetsExchangeInfo() + { + var eid = Composer.Instance.GetExportedValueByTypeName("TemplateExchangeInfoDownloader"); + var tickers = eid.Get().ToList(); + + Assert.IsTrue(tickers.Any()); + var previousTicker = string.Empty; + foreach (var tickerLine in tickers) + { + Assert.IsTrue(tickerLine.StartsWith(eid.Market, StringComparison.OrdinalIgnoreCase)); + var data = tickerLine.Split(","); + Assert.AreEqual(10, data.Length); + var ticker = data[1]; + Assert.Greater(string.Compare(ticker, previousTicker, StringComparison.Ordinal), 0); + previousTicker = ticker; + } + } + } +} \ No newline at end of file diff --git a/QuantConnect.TemplateBrokerage.Tests/TestSetup.cs b/QuantConnect.TemplateBrokerage.Tests/TestSetup.cs new file mode 100644 index 0000000..a989af2 --- /dev/null +++ b/QuantConnect.TemplateBrokerage.Tests/TestSetup.cs @@ -0,0 +1,78 @@ +/* + * 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.IO; +using NUnit.Framework; +using System.Collections; +using QuantConnect.Logging; +using QuantConnect.Configuration; + +namespace QuantConnect.Brokerages.Template.Tests +{ + [TestFixture] + public class TestSetup + { + [Test, TestCaseSource(nameof(TestParameters))] + public void TestSetupCase() + { + } + + public static void ReloadConfiguration() + { + // nunit 3 sets the current folder to a temp folder we need it to be the test bin output folder + var dir = TestContext.CurrentContext.TestDirectory; + Environment.CurrentDirectory = dir; + Directory.SetCurrentDirectory(dir); + // reload config from current path + Config.Reset(); + + var environment = Environment.GetEnvironmentVariables(); + foreach (DictionaryEntry entry in environment) + { + var envKey = entry.Key.ToString(); + var value = entry.Value.ToString(); + + if (envKey.StartsWith("QC_")) + { + var key = envKey.Substring(3).Replace("_", "-").ToLower(); + + Log.Trace($"TestSetup(): Updating config setting '{key}' from environment var '{envKey}'"); + Config.Set(key, value); + } + } + + // resets the version among other things + Globals.Reset(); + } + + private static void SetUp() + { + Log.LogHandler = new CompositeLogHandler(); + Log.Trace("TestSetup(): starting..."); + ReloadConfiguration(); + Log.DebuggingEnabled = Config.GetBool("debug-mode"); + } + + private static TestCaseData[] TestParameters + { + get + { + SetUp(); + return new [] { new TestCaseData() }; + } + } + } +} diff --git a/QuantConnect.TemplateBrokerage.Tests/config.json b/QuantConnect.TemplateBrokerage.Tests/config.json new file mode 100644 index 0000000..6e443af --- /dev/null +++ b/QuantConnect.TemplateBrokerage.Tests/config.json @@ -0,0 +1,3 @@ +{ + "data-folder": "../../../../Lean/Data/" +} diff --git a/QuantConnect.TemplateBrokerage.ToolBox/Program.cs b/QuantConnect.TemplateBrokerage.ToolBox/Program.cs new file mode 100644 index 0000000..23282fd --- /dev/null +++ b/QuantConnect.TemplateBrokerage.ToolBox/Program.cs @@ -0,0 +1,53 @@ +/* + * 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 QuantConnect.ToolBox; +using QuantConnect.Configuration; +using static QuantConnect.Configuration.ApplicationParser; + +namespace QuantConnect.Brokerages.Template.ToolBox +{ + static class Program + { + static void Main(string[] args) + { + var optionsObject = ToolboxArgumentParser.ParseArguments(args); + if (optionsObject.Count == 0) + { + PrintMessageAndExit(); + } + + if (!optionsObject.TryGetValue("app", out var targetApp)) + { + PrintMessageAndExit(1, "ERROR: --app value is required"); + } + + var targetAppName = targetApp.ToString(); + if (targetAppName.Contains("download") || targetAppName.Contains("dl")) + { + var downloader = new TemplateBrokerageDownloader(); + } + else if (targetAppName.Contains("updater") || targetAppName.EndsWith("spu")) + { + new ExchangeInfoUpdater(new TemplateExchangeInfoDownloader()) + .Run(); + } + else + { + PrintMessageAndExit(1, "ERROR: Unrecognized --app value"); + } + } + } +} \ No newline at end of file diff --git a/QuantConnect.TemplateBrokerage.ToolBox/QuantConnect.TemplateBrokerage.ToolBox.csproj b/QuantConnect.TemplateBrokerage.ToolBox/QuantConnect.TemplateBrokerage.ToolBox.csproj new file mode 100644 index 0000000..0aaf69a --- /dev/null +++ b/QuantConnect.TemplateBrokerage.ToolBox/QuantConnect.TemplateBrokerage.ToolBox.csproj @@ -0,0 +1,33 @@ + + + + Release + AnyCPU + Exe + net6.0 + Copyright © 2021 + bin\$(Configuration)\ + QuantConnect.Brokerages.Template.ToolBox + QuantConnect.Brokerages.Template.ToolBox + QuantConnect.Brokerages.Template.ToolBox + QuantConnect.Brokerages.Template.ToolBox + false + true + false + QuantConnect LEAN Template Brokerage: Brokerage Template toolbox plugin for Lean + + + full + bin\Debug\ + + + pdbonly + bin\Release\ + + + + + + + + diff --git a/QuantConnect.TemplateBrokerage.ToolBox/TemplateBrokerageDownloader.cs b/QuantConnect.TemplateBrokerage.ToolBox/TemplateBrokerageDownloader.cs new file mode 100644 index 0000000..55f2077 --- /dev/null +++ b/QuantConnect.TemplateBrokerage.ToolBox/TemplateBrokerageDownloader.cs @@ -0,0 +1,37 @@ +/* + * 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 QuantConnect.Data; +using System.Collections.Generic; + +namespace QuantConnect.Brokerages.Template.ToolBox +{ + /// + /// Template Brokerage Data Downloader implementation + /// + public class TemplateBrokerageDownloader : IDataDownloader + { + /// + /// Get historical data enumerable for a single symbol, type and resolution given this start and end time (in UTC). + /// + /// model class for passing in parameters for historical data + /// Enumerable of base data for this symbol + public IEnumerable Get(DataDownloaderGetParameters dataDownloaderGetParameters) + { + throw new NotImplementedException(); + } + } +} \ No newline at end of file diff --git a/QuantConnect.TemplateBrokerage.ToolBox/TemplateExchangeInfoDownloader.cs b/QuantConnect.TemplateBrokerage.ToolBox/TemplateExchangeInfoDownloader.cs new file mode 100644 index 0000000..652d8cc --- /dev/null +++ b/QuantConnect.TemplateBrokerage.ToolBox/TemplateExchangeInfoDownloader.cs @@ -0,0 +1,40 @@ +/* + * 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 QuantConnect.ToolBox; +using System.Collections.Generic; + +namespace QuantConnect.Brokerages.Template.ToolBox +{ + /// + /// Template Brokerage implementation of + /// + public class TemplateExchangeInfoDownloader : IExchangeInfoDownloader + { + /// + /// Market + /// + public string Market => throw new System.NotImplementedException(); + + /// + /// Get exchange info coma-separated data + /// + /// Enumerable of exchange info for this market + public IEnumerable Get() + { + throw new System.NotImplementedException(); + } + } +} \ No newline at end of file diff --git a/QuantConnect.TemplateBrokerage.sln b/QuantConnect.TemplateBrokerage.sln new file mode 100644 index 0000000..8cf2e70 --- /dev/null +++ b/QuantConnect.TemplateBrokerage.sln @@ -0,0 +1,73 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 16 +VisualStudioVersion = 16.0.31205.134 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "QuantConnect.TemplateBrokerage", "QuantConnect.TemplateBrokerage\QuantConnect.TemplateBrokerage.csproj", "{7C447DDD-D30D-46C3-A341-2D768CCEEC10}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "QuantConnect", "..\Lean\Common\QuantConnect.csproj", "{477827EE-5908-48AB-B6A4-DAB6E85D96DF}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "QuantConnect.Logging", "..\Lean\Logging\QuantConnect.Logging.csproj", "{86BE4507-719A-466A-B3E7-4840BBD1AAA8}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "QuantConnect.Configuration", "..\Lean\Configuration\QuantConnect.Configuration.csproj", "{2FBFC99D-1404-49CD-86C5-2EFF9EDE78BC}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "QuantConnect.Brokerages", "..\Lean\Brokerages\QuantConnect.Brokerages.csproj", "{764AE24F-232B-4D0D-8B04-DFE3A4907D38}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "QuantConnect.Tests", "..\Lean\Tests\QuantConnect.Tests.csproj", "{40B784EE-9297-4715-8C8F-829DFE858BEF}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "QuantConnect.TemplateBrokerage.Tests", "QuantConnect.TemplateBrokerage.Tests\QuantConnect.TemplateBrokerage.Tests.csproj", "{8793CDDF-3348-473F-98AF-68C6EBFA5014}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "QuantConnect.TemplateBrokerage.ToolBox", "QuantConnect.TemplateBrokerage.ToolBox\QuantConnect.TemplateBrokerage.ToolBox.csproj", "{1AB073F2-6881-48C3-AC07-A042D0B51E6B}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "QuantConnect.ToolBox", "..\Lean\ToolBox\QuantConnect.ToolBox.csproj", "{88885A3A-5028-4EFB-9244-47FDB04725CE}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {7C447DDD-D30D-46C3-A341-2D768CCEEC10}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {7C447DDD-D30D-46C3-A341-2D768CCEEC10}.Debug|Any CPU.Build.0 = Debug|Any CPU + {7C447DDD-D30D-46C3-A341-2D768CCEEC10}.Release|Any CPU.ActiveCfg = Release|Any CPU + {7C447DDD-D30D-46C3-A341-2D768CCEEC10}.Release|Any CPU.Build.0 = Release|Any CPU + {477827EE-5908-48AB-B6A4-DAB6E85D96DF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {477827EE-5908-48AB-B6A4-DAB6E85D96DF}.Debug|Any CPU.Build.0 = Debug|Any CPU + {477827EE-5908-48AB-B6A4-DAB6E85D96DF}.Release|Any CPU.ActiveCfg = Release|Any CPU + {477827EE-5908-48AB-B6A4-DAB6E85D96DF}.Release|Any CPU.Build.0 = Release|Any CPU + {86BE4507-719A-466A-B3E7-4840BBD1AAA8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {86BE4507-719A-466A-B3E7-4840BBD1AAA8}.Debug|Any CPU.Build.0 = Debug|Any CPU + {86BE4507-719A-466A-B3E7-4840BBD1AAA8}.Release|Any CPU.ActiveCfg = Release|Any CPU + {86BE4507-719A-466A-B3E7-4840BBD1AAA8}.Release|Any CPU.Build.0 = Release|Any CPU + {2FBFC99D-1404-49CD-86C5-2EFF9EDE78BC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {2FBFC99D-1404-49CD-86C5-2EFF9EDE78BC}.Debug|Any CPU.Build.0 = Debug|Any CPU + {2FBFC99D-1404-49CD-86C5-2EFF9EDE78BC}.Release|Any CPU.ActiveCfg = Release|Any CPU + {2FBFC99D-1404-49CD-86C5-2EFF9EDE78BC}.Release|Any CPU.Build.0 = Release|Any CPU + {764AE24F-232B-4D0D-8B04-DFE3A4907D38}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {764AE24F-232B-4D0D-8B04-DFE3A4907D38}.Debug|Any CPU.Build.0 = Debug|Any CPU + {764AE24F-232B-4D0D-8B04-DFE3A4907D38}.Release|Any CPU.ActiveCfg = Release|Any CPU + {764AE24F-232B-4D0D-8B04-DFE3A4907D38}.Release|Any CPU.Build.0 = Release|Any CPU + {40B784EE-9297-4715-8C8F-829DFE858BEF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {40B784EE-9297-4715-8C8F-829DFE858BEF}.Debug|Any CPU.Build.0 = Debug|Any CPU + {40B784EE-9297-4715-8C8F-829DFE858BEF}.Release|Any CPU.ActiveCfg = Release|Any CPU + {40B784EE-9297-4715-8C8F-829DFE858BEF}.Release|Any CPU.Build.0 = Release|Any CPU + {8793CDDF-3348-473F-98AF-68C6EBFA5014}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {8793CDDF-3348-473F-98AF-68C6EBFA5014}.Debug|Any CPU.Build.0 = Debug|Any CPU + {8793CDDF-3348-473F-98AF-68C6EBFA5014}.Release|Any CPU.ActiveCfg = Release|Any CPU + {8793CDDF-3348-473F-98AF-68C6EBFA5014}.Release|Any CPU.Build.0 = Release|Any CPU + {1AB073F2-6881-48C3-AC07-A042D0B51E6B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {1AB073F2-6881-48C3-AC07-A042D0B51E6B}.Debug|Any CPU.Build.0 = Debug|Any CPU + {1AB073F2-6881-48C3-AC07-A042D0B51E6B}.Release|Any CPU.ActiveCfg = Release|Any CPU + {1AB073F2-6881-48C3-AC07-A042D0B51E6B}.Release|Any CPU.Build.0 = Release|Any CPU + {88885A3A-5028-4EFB-9244-47FDB04725CE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {88885A3A-5028-4EFB-9244-47FDB04725CE}.Debug|Any CPU.Build.0 = Debug|Any CPU + {88885A3A-5028-4EFB-9244-47FDB04725CE}.Release|Any CPU.ActiveCfg = Release|Any CPU + {88885A3A-5028-4EFB-9244-47FDB04725CE}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {61010DD6-6D0C-4324-8137-1EDF35F16864} + EndGlobalSection +EndGlobal diff --git a/QuantConnect.TemplateBrokerage/QuantConnect.TemplateBrokerage.csproj b/QuantConnect.TemplateBrokerage/QuantConnect.TemplateBrokerage.csproj new file mode 100644 index 0000000..8980ff5 --- /dev/null +++ b/QuantConnect.TemplateBrokerage/QuantConnect.TemplateBrokerage.csproj @@ -0,0 +1,32 @@ + + + Release + AnyCPU + net6.0 + QuantConnect.Brokerages.Template + QuantConnect.Brokerages.Template + QuantConnect.Brokerages.Template + QuantConnect.Brokerages.Template + Library + bin\$(Configuration)\ + false + true + false + QuantConnect LEAN Template Brokerage: Brokerage Template plugin for Lean + + + full + bin\Debug\ + + + pdbonly + bin\Release\ + + + + + + + + + \ No newline at end of file diff --git a/QuantConnect.TemplateBrokerage/TemplateBrokerage.cs b/QuantConnect.TemplateBrokerage/TemplateBrokerage.cs new file mode 100644 index 0000000..fe21cfa --- /dev/null +++ b/QuantConnect.TemplateBrokerage/TemplateBrokerage.cs @@ -0,0 +1,259 @@ +/* + * 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 QuantConnect.Data; +using QuantConnect.Util; +using QuantConnect.Orders; +using QuantConnect.Packets; +using QuantConnect.Interfaces; +using QuantConnect.Securities; +using System.Collections.Generic; + +namespace QuantConnect.Brokerages.Template +{ + [BrokerageFactory(typeof(TemplateBrokerageFactory))] + public class TemplateBrokerage : Brokerage, IDataQueueHandler, IDataQueueUniverseProvider + { + private readonly IDataAggregator _aggregator; + private readonly EventBasedDataQueueHandlerSubscriptionManager _subscriptionManager; + + /// + /// Returns true if we're currently connected to the broker + /// + public override bool IsConnected { get; } + + /// + /// Parameterless constructor for brokerage + /// + /// This parameterless constructor is required for brokerages implementing + public TemplateBrokerage() + : this(Composer.Instance.GetPart()) + { + } + + /// + /// Creates a new instance + /// + /// consolidate ticks + public TemplateBrokerage(IDataAggregator aggregator) : base("TemplateBrokerage") + { + _aggregator = aggregator; + _subscriptionManager = new EventBasedDataQueueHandlerSubscriptionManager(); + _subscriptionManager.SubscribeImpl += (s, t) => Subscribe(s); + _subscriptionManager.UnsubscribeImpl += (s, t) => Unsubscribe(s); + + // Useful for some brokerages: + + // Brokerage helper class to lock websocket message stream while executing an action, for example placing an order + // avoid race condition with placing an order and getting filled events before finished placing + // _messageHandler = new BrokerageConcurrentMessageHandler<>(); + + // Rate gate limiter useful for API/WS calls + // _connectionRateLimiter = new RateGate(); + } + + #region IDataQueueHandler + + /// + /// Subscribe to the specified configuration + /// + /// defines the parameters to subscribe to a data feed + /// handler to be fired on new data available + /// The new enumerator for this subscription request + public IEnumerator Subscribe(SubscriptionDataConfig dataConfig, EventHandler newDataAvailableHandler) + { + if (!CanSubscribe(dataConfig.Symbol)) + { + return null; + } + + var enumerator = _aggregator.Add(dataConfig, newDataAvailableHandler); + _subscriptionManager.Subscribe(dataConfig); + + return enumerator; + } + + /// + /// Removes the specified configuration + /// + /// Subscription config to be removed + public void Unsubscribe(SubscriptionDataConfig dataConfig) + { + _subscriptionManager.Unsubscribe(dataConfig); + _aggregator.Remove(dataConfig); + } + + /// + /// Sets the job we're subscribing for + /// + /// Job we're subscribing for + public void SetJob(LiveNodePacket job) + { + throw new NotImplementedException(); + } + + #endregion + + #region Brokerage + + /// + /// Gets all open orders on the account. + /// NOTE: The order objects returned do not have QC order IDs. + /// + /// The open orders returned from IB + public override List GetOpenOrders() + { + throw new NotImplementedException(); + } + + /// + /// Gets all holdings for the account + /// + /// The current holdings from the account + public override List GetAccountHoldings() + { + throw new NotImplementedException(); + } + + /// + /// Gets the current cash balance for each currency held in the brokerage account + /// + /// The current cash balance for each currency available for trading + public override List GetCashBalance() + { + throw new NotImplementedException(); + } + + /// + /// Places a new order and assigns a new broker ID to the order + /// + /// The order to be placed + /// True if the request for a new order has been placed, false otherwise + public override bool PlaceOrder(Order order) + { + throw new NotImplementedException(); + } + + /// + /// Updates the order with the same id + /// + /// The new order information + /// True if the request was made for the order to be updated, false otherwise + public override bool UpdateOrder(Order order) + { + throw new NotImplementedException(); + } + + /// + /// Cancels the order with the specified ID + /// + /// The order to cancel + /// True if the request was made for the order to be canceled, false otherwise + public override bool CancelOrder(Order order) + { + throw new NotImplementedException(); + } + + /// + /// Connects the client to the broker's remote servers + /// + public override void Connect() + { + throw new NotImplementedException(); + } + + /// + /// Disconnects the client from the broker's remote servers + /// + public override void Disconnect() + { + throw new NotImplementedException(); + } + + #endregion + + #region IDataQueueUniverseProvider + + /// + /// Method returns a collection of Symbols that are available at the data source. + /// + /// Symbol to lookup + /// Include expired contracts + /// Expected security currency(if any) + /// Enumerable of Symbols, that are associated with the provided Symbol + public IEnumerable LookupSymbols(Symbol symbol, bool includeExpired, string securityCurrency = null) + { + throw new NotImplementedException(); + } + + /// + /// Returns whether selection can take place or not. + /// + /// This is useful to avoid a selection taking place during invalid times, for example IB reset times or when not connected, + /// because if allowed selection would fail since IB isn't running and would kill the algorithm + /// True if selection can take place + public bool CanPerformSelection() + { + throw new NotImplementedException(); + } + + #endregion + + private bool CanSubscribe(Symbol symbol) + { + if (symbol.Value.IndexOfInvariant("universe", true) != -1 || symbol.IsCanonical()) + { + return false; + } + + throw new NotImplementedException(); + } + + /// + /// Adds the specified symbols to the subscription + /// + /// The symbols to be added keyed by SecurityType + private bool Subscribe(IEnumerable symbols) + { + throw new NotImplementedException(); + } + + /// + /// Removes the specified symbols to the subscription + /// + /// The symbols to be removed keyed by SecurityType + private bool Unsubscribe(IEnumerable symbols) + { + throw new NotImplementedException(); + } + + /// + /// Gets the history for the requested symbols + /// + /// + /// The historical data request + /// An enumerable of bars covering the span specified in the request + public override IEnumerable GetHistory(Data.HistoryRequest request) + { + if (!CanSubscribe(request.Symbol)) + { + return null; // Should consistently return null instead of an empty enumerable + } + + throw new NotImplementedException(); + } + } +} diff --git a/QuantConnect.TemplateBrokerage/TemplateBrokerageFactory.cs b/QuantConnect.TemplateBrokerage/TemplateBrokerageFactory.cs new file mode 100644 index 0000000..29a0dbd --- /dev/null +++ b/QuantConnect.TemplateBrokerage/TemplateBrokerageFactory.cs @@ -0,0 +1,74 @@ +/* + * 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 QuantConnect.Packets; +using QuantConnect.Brokerages; +using QuantConnect.Interfaces; +using QuantConnect.Securities; +using System.Collections.Generic; + +namespace QuantConnect.Brokerages.Template +{ + /// + /// Provides a template implementation of BrokerageFactory + /// + public class TemplateBrokerageFactory : BrokerageFactory + { + /// + /// Gets the brokerage data required to run the brokerage from configuration/disk + /// + /// + /// The implementation of this property will create the brokerage data dictionary required for + /// running live jobs. See + /// + public override Dictionary BrokerageData { get; } + + /// + /// Initializes a new instance of the class + /// + public TemplateBrokerageFactory() : base(typeof(TemplateBrokerage)) + { + } + + /// + /// Gets a brokerage model that can be used to model this brokerage's unique behaviors + /// + /// The order provider + public override IBrokerageModel GetBrokerageModel(IOrderProvider orderProvider) + { + throw new NotImplementedException(); + } + + /// + /// Creates a new IBrokerage instance + /// + /// The job packet to create the brokerage for + /// The algorithm instance + /// A new brokerage instance + public override IBrokerage CreateBrokerage(LiveNodePacket job, IAlgorithm algorithm) + { + throw new NotImplementedException(); + } + + /// + /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. + /// + public override void Dispose() + { + throw new NotImplementedException(); + } + } +} \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..e4bcaeb --- /dev/null +++ b/README.md @@ -0,0 +1,10 @@ +![lean-brokerage-template](https://user-images.githubusercontent.com/18473240/131904120-f67dab9c-cc6f-4c08-83e9-5d3ffafdb85d.png) + + +# Lean.Brokerages.Template + +[![Build Status](https://github.com/QuantConnect/Lean.Brokerages.Template/workflows/Build%20%26%20Test/badge.svg)](https://github.com/QuantConnect/Lean.Brokerages.Template/actions?query=workflow%3A%22Build%20%26%20Test%22) + +Template Brokerage Plugin for [Lean](https://github.com/QuantConnect/Lean) + +See the [brokerage development guide](https://www.quantconnect.com/tutorials/open-source/brokerage-development-guide)