Skip to content

Commit 330435e

Browse files
CI, Tests and Minor fixes (#12)
* fix minor issues - CI calls dydx sln files - populate dydx clientId to the dict for futher manipulation (cancel) - update config defaults to mainnet * fix minor issues - handle missed events - support gtc and day tif - increment sequence - enable tests * fix trigger price calculation for stop orders * return false if cancellation was not submitted, allow brokerage transaction handler to emit event for us * emit Submitted event for orders when FILL arrived faster * dispose items * Update test configurations and workflows to use dYdX testnet * our own testnet creds * return qc env variables
1 parent 5df34a3 commit 330435e

File tree

15 files changed

+240
-218
lines changed

15 files changed

+240
-218
lines changed

.github/workflows/gh-actions.yml

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,10 @@ on:
77
jobs:
88
build:
99
runs-on: ubuntu-24.04
10+
env:
11+
QC_DYDX_ADDRESS: ${{ secrets.QC_DYDX_ADDRESS }}
12+
QC_DYDX_PRIVATE_KEY: ${{ secrets.QC_DYDX_PRIVATE_KEY }}
13+
QC_DYDX_SUBACCOUNT_NUMBER: ${{ secrets.QC_DYDX_SUBACCOUNT_NUMBER }}
1014
steps:
1115
- name: Checkout
1216
uses: actions/checkout@v2
@@ -41,10 +45,10 @@ jobs:
4145
- uses: addnab/docker-run-action@v3
4246
with:
4347
image: quantconnect/lean:foundation
44-
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 }}
48+
options: --workdir /__w/Lean.Brokerages.dYdX/Lean.Brokerages.dYdX -v /home/runner/work:/__w -e QC_DYDX_ADDRESS -e QC_DYDX_PRIVATE_KEY -e QC_DYDX_SUBACCOUNT_NUMBER -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 }}
4549
shell: bash
4650
run: |
4751
# Build
48-
dotnet build /p:Configuration=Release /v:quiet /p:WarningLevel=1 QuantConnect.TemplateBrokerage.sln && \
52+
dotnet build /p:Configuration=Release /v:quiet /p:WarningLevel=1 QuantConnect.dYdXBrokerage.sln && \
4953
# Run Tests
50-
dotnet test ./QuantConnect.TemplateBrokerage.Tests/bin/Release/QuantConnect.Brokerages.Template.Tests.dll
54+
dotnet test ./QuantConnect.dYdXBrokerage.Tests/bin/Release/QuantConnect.Brokerages.dYdX.Tests.dll

QuantConnect.dYdXBrokerage.Tests/config.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@
22
"data-folder": "../../../../Lean/Data/",
33

44
// dydx configuration
5-
"dydx-private-key-hex": "e92a6595c934c991d3b3e987ea9b3125bf61a076deab3a9cb519787b7b3e8d77",
6-
"dydx-address": "dydx14zzueazeh0hj67cghhf9jypslcf9sh2n5k6art", //DYDX_TEST_ADDRESS
5+
"dydx-private-key-hex": "0x933fd548827550f2a3560cf1ec0f30823ba7c9699a42ed6d8978726791ce8aef",
6+
"dydx-address": "dydx1067v37ykkf7muydw77lzp3m8j05ewpe3p33fuc", //DYDX_TEST_ADDRESS
77
"dydx-subaccount-number": 0,
88
"dydx-node-api-rest": "https://test-dydx-rest.kingnodes.com",
99
"dydx-node-api-grpc": "https://test-dydx-grpc.kingnodes.com:443",

QuantConnect.dYdXBrokerage.Tests/dYdXBrokerageDataQueueHandlerTests.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -67,8 +67,8 @@ public void StreamsData(Symbol symbol, Resolution resolution, bool throwsExcepti
6767
};
6868
}
6969

70-
var trade = new ManualResetEvent(false);
71-
var quote = new ManualResetEvent(false);
70+
using var trade = new ManualResetEvent(false);
71+
using var quote = new ManualResetEvent(false);
7272
foreach (var config in configs)
7373
{
7474
ProcessFeed(brokerage.Subscribe(config, (s, e) => { }),

QuantConnect.dYdXBrokerage.Tests/dYdXBrokerageHistoryProviderTests.cs

Lines changed: 90 additions & 92 deletions
Original file line numberDiff line numberDiff line change
@@ -14,143 +14,141 @@
1414
*/
1515

1616
using System;
17+
using System.Collections.Generic;
1718
using System.Linq;
1819
using NUnit.Framework;
19-
using QuantConnect.Brokerages.dYdX;
2020
using QuantConnect.Configuration;
2121
using QuantConnect.Data;
22-
using QuantConnect.Tests;
2322
using QuantConnect.Logging;
2423
using QuantConnect.Securities;
2524
using QuantConnect.Data.Market;
26-
using QuantConnect.Lean.Engine.DataFeeds;
2725
using QuantConnect.Lean.Engine.HistoricalData;
26+
using QuantConnect.Tests;
2827

2928
namespace QuantConnect.Brokerages.dYdX.Tests
3029
{
31-
[TestFixture, Ignore("Not implemented")]
30+
[TestFixture]
3231
public class dYdXBrokerageHistoryProviderTests
3332
{
34-
private static TestCaseData[] TestParameters
33+
private static readonly Symbol _btcusd = Symbol.Create("BTCUSD", SecurityType.CryptoFuture, Market.dYdX);
34+
35+
private static IEnumerable<TestCaseData> TestParameters
3536
{
3637
get
3738
{
38-
return new[]
39-
{
40-
// valid parameters, example:
41-
new TestCaseData(Symbols.BTCUSD, Resolution.Tick, TimeSpan.FromMinutes(1), TickType.Quote,
42-
typeof(Tick), false),
43-
new TestCaseData(Symbols.BTCUSD, Resolution.Minute, TimeSpan.FromMinutes(10), TickType.Quote,
44-
typeof(QuoteBar), false),
45-
new TestCaseData(Symbols.BTCUSD, Resolution.Daily, TimeSpan.FromDays(10), TickType.Quote,
46-
typeof(QuoteBar), false),
47-
48-
new TestCaseData(Symbols.BTCUSD, Resolution.Tick, TimeSpan.FromMinutes(1), TickType.Trade,
49-
typeof(Tick), false),
50-
new TestCaseData(Symbols.BTCUSD, Resolution.Minute, TimeSpan.FromMinutes(10), TickType.Trade,
39+
TestGlobals.Initialize();
40+
41+
return
42+
[
43+
new(_btcusd, Resolution.Minute, TimeSpan.FromMinutes(10), TickType.Trade,
44+
typeof(TradeBar), false),
45+
new(_btcusd, Resolution.Hour, TimeSpan.FromHours(10), TickType.Trade,
5146
typeof(TradeBar), false),
52-
new TestCaseData(Symbols.BTCUSD, Resolution.Daily, TimeSpan.FromDays(10), TickType.Trade,
47+
new(_btcusd, Resolution.Daily, TimeSpan.FromDays(10), TickType.Trade,
5348
typeof(TradeBar), false),
5449

55-
// invalid parameter, validate SecurityType more accurate
56-
new TestCaseData(Symbols.SPY, Resolution.Hour, TimeSpan.FromHours(14), TickType.Quote,
50+
new(_btcusd, Resolution.Minute, TimeSpan.FromMinutes(10),
51+
TickType.OpenInterest,
52+
typeof(OpenInterest), false),
53+
new(_btcusd, Resolution.Hour, TimeSpan.FromHours(10), TickType.OpenInterest,
54+
typeof(OpenInterest), false),
55+
new(_btcusd, Resolution.Daily, TimeSpan.FromDays(10), TickType.OpenInterest,
56+
typeof(OpenInterest), false),
57+
58+
// invalid parameter, return null if TickType.Quote
59+
new(_btcusd, Resolution.Daily, TimeSpan.FromDays(10), TickType.Quote,
5760
typeof(QuoteBar), true),
5861

59-
/// New Listed Symbol on Brokerage <see cref="Slice.SymbolChangedEvents"/>
60-
new TestCaseData(Symbol.Create("SUSHIGBP", SecurityType.Crypto, Market.Coinbase), Resolution.Minute,
61-
TimeSpan.FromHours(2), TickType.Trade, typeof(TradeBar), false),
62+
// invalid parameter, validate SecurityType more accurate
63+
new(Symbols.SPY, Resolution.Hour, TimeSpan.FromHours(14), TickType.Quote,
64+
typeof(QuoteBar), true),
6265

63-
/// Symbol was delisted form Brokerage (can return history data or not) <see cref="Slice.Delistings"/>
64-
new TestCaseData(Symbol.Create("SNTUSD", SecurityType.Crypto, Market.Coinbase), Resolution.Daily,
65-
TimeSpan.FromDays(14), TickType.Trade, typeof(TradeBar), true),
66-
};
66+
// Symbol was delisted form Brokerage (can return history data or not) <see cref="Slice.Delistings"/>
67+
new(Symbol.Create("MATICUSD", SecurityType.CryptoFuture, Market.dYdX),
68+
Resolution.Daily,
69+
TimeSpan.FromDays(14), TickType.Trade, typeof(TradeBar), true)
70+
];
6771
}
6872
}
6973

7074
[Test, TestCaseSource(nameof(TestParameters))]
71-
public void GetsHistory(Symbol symbol, Resolution resolution, TimeSpan period, TickType tickType, Type dataType,
72-
bool throwsException)
75+
public void GetsHistory(Symbol symbol, Resolution resolution, TimeSpan period, TickType tickType, Type dataType, bool invalidRequest)
7376
{
74-
TestDelegate test = () =>
77+
var brokerage = CreateBrokerage();
78+
79+
var historyProvider = new BrokerageHistoryProvider();
80+
historyProvider.SetBrokerage(brokerage);
81+
historyProvider.Initialize(new HistoryProviderInitializeParameters(null, null, null,
82+
null, null, null, null,
83+
false, null, null, new AlgorithmSettings()));
84+
85+
var marketHoursDatabase = MarketHoursDatabase.FromDataFolder();
86+
var now = DateTime.UtcNow;
87+
var requests = new[]
7588
{
76-
var brokerage = CreateBrokerage();
89+
new HistoryRequest(now.Add(-period),
90+
now,
91+
dataType,
92+
symbol,
93+
resolution,
94+
marketHoursDatabase.GetExchangeHours(symbol.ID.Market, symbol, symbol.SecurityType),
95+
marketHoursDatabase.GetDataTimeZone(symbol.ID.Market, symbol, symbol.SecurityType),
96+
resolution,
97+
false,
98+
false,
99+
DataNormalizationMode.Adjusted,
100+
tickType)
101+
};
77102

78-
var historyProvider = new BrokerageHistoryProvider();
79-
historyProvider.SetBrokerage(brokerage);
80-
historyProvider.Initialize(new HistoryProviderInitializeParameters(null, null, null,
81-
null, null, null, null,
82-
false, null, null, null));
103+
var historyArray = historyProvider.GetHistory(requests, TimeZones.Utc)?.ToArray();
104+
if (invalidRequest)
105+
{
106+
Assert.Null(historyArray);
107+
return;
108+
}
83109

84-
var marketHoursDatabase = MarketHoursDatabase.FromDataFolder();
85-
var now = DateTime.UtcNow;
86-
var requests = new[]
87-
{
88-
new HistoryRequest(now.Add(-period),
89-
now,
90-
dataType,
91-
symbol,
92-
resolution,
93-
marketHoursDatabase.GetExchangeHours(symbol.ID.Market, symbol, symbol.SecurityType),
94-
marketHoursDatabase.GetDataTimeZone(symbol.ID.Market, symbol, symbol.SecurityType),
95-
resolution,
96-
false,
97-
false,
98-
DataNormalizationMode.Adjusted,
99-
tickType)
100-
};
101-
102-
var historyArray = historyProvider.GetHistory(requests, TimeZones.Utc).ToArray();
103-
foreach (var slice in historyArray)
110+
Assert.NotNull(historyArray);
111+
foreach (var slice in historyArray)
112+
{
113+
if (resolution == Resolution.Tick)
104114
{
105-
if (resolution == Resolution.Tick)
106-
{
107-
foreach (var tick in slice.Ticks[symbol])
108-
{
109-
Log.Debug($"{tick}");
110-
}
111-
}
112-
else if (slice.QuoteBars.TryGetValue(symbol, out var quoteBar))
113-
{
114-
Log.Debug($"{quoteBar}");
115-
}
116-
else if (slice.Bars.TryGetValue(symbol, out var tradeBar))
115+
foreach (var tick in slice.Ticks[symbol])
117116
{
118-
Log.Debug($"{tradeBar}");
117+
Log.Debug($"{tick}");
119118
}
120119
}
121-
122-
if (historyProvider.DataPointCount > 0)
120+
else if (slice.QuoteBars.TryGetValue(symbol, out var quoteBar))
123121
{
124-
// Ordered by time
125-
Assert.That(historyArray, Is.Ordered.By("Time"));
126-
127-
// No repeating bars
128-
var timesArray = historyArray.Select(x => x.Time).ToArray();
129-
Assert.AreEqual(timesArray.Length, timesArray.Distinct().Count());
122+
Log.Debug($"{quoteBar}");
123+
}
124+
else if (slice.Bars.TryGetValue(symbol, out var tradeBar))
125+
{
126+
Log.Debug($"{tradeBar}");
130127
}
131-
132-
Log.Trace("Data points retrieved: " + historyProvider.DataPointCount);
133-
};
134-
135-
if (throwsException)
136-
{
137-
Assert.Throws<ArgumentException>(test);
138128
}
139-
else
129+
130+
if (historyProvider.DataPointCount > 0)
140131
{
141-
Assert.DoesNotThrow(test);
132+
// Ordered by time
133+
Assert.That(historyArray, Is.Ordered.By("Time"));
134+
135+
// No repeating bars
136+
var timesArray = historyArray.Select(x => x.Time).ToArray();
137+
Assert.AreEqual(timesArray.Length, timesArray.Distinct().Count());
142138
}
143139

140+
Log.Trace("Data points retrieved: " + historyProvider.DataPointCount);
141+
144142
Brokerage CreateBrokerage()
145143
{
146144
var privateKey = Config.Get("dydx-private-key-hex");
147145
var address = Config.Get("dydx-address");
148146
var subaccountNumber = checked((uint)Config.GetInt("dydx-subaccount-number"));
149-
var nodeUrlRest = Config.Get("dydx-node-api-rest");
150-
var nodeUrlGrpc = Config.Get("dydx-node-api-grpc");
151-
var indexerUrlRest = Config.Get("dydx-indexer-api-rest");
152-
var indexerUrlWss = Config.Get("dydx-indexer-api-wss");
153-
var chainId = Config.Get("dydx-chain-id");
147+
var nodeUrlRest = Config.Get("dydx-node-api-rest", "https://test-dydx-rest.kingnodes.com");
148+
var nodeUrlGrpc = Config.Get("dydx-node-api-grpc", "https://test-dydx-grpc.kingnodes.com:443");
149+
var indexerUrlRest = Config.Get("dydx-indexer-api-rest", "https://indexer.v4testnet.dydx.exchange/v4");
150+
var indexerUrlWss = Config.Get("dydx-indexer-api-wss", "wss://indexer.v4testnet.dydx.exchange/v4/ws");
151+
var chainId = Config.Get("dydx-chain-id", "dydx-testnet-4");
154152

155153
return new dYdXBrokerage(
156154
privateKey,

QuantConnect.dYdXBrokerage.Tests/dYdXBrokerageSymbolMapperTests.cs

Lines changed: 0 additions & 35 deletions
This file was deleted.

0 commit comments

Comments
 (0)