Template Brokerage Plugin for Lean
See the brokerage development guide
-
Review documentation for the new brokerage integration.
-
Approve supported Security types (e.g., Equity, Index, Option).
-
Approve support Order types: Market, Limit, Stop, StopLimit, TrailingStop, MarketOnClose, TrailingStopLimit, etc.
-
Create a new brokerage development account.
-
Generate API keys.
-
🍴📦Fork QuantConnect brokerage repository.
-
Rename all template to new brokerage names by a skeleton.
- for instance:
TemplateBrokerage.cs
->BinanceBrokerage.cs
public class TemplateBrokerage
->public class InteractiveBrokersBrokerage
- for instance:
-
Remove: not used parts (for instance: downloader lean has generic now, but some brokerages support downloading trading pairs process like some crypto exchanges) - Lean download data provider source, Bybit Exchange Info Downloader
-
Implement API connection (simple request) infrastructure (generic method that send GET/POST requests)
-
If brokerage support several steps of authentication like OAuth 2 - TradeStation example
-
Implement URL method to generate Authorization URL - TradeStation example
-
🧪 Unit test: to get Authorization URL - TradeStation example
-
Create a method to automatically generate a new refresh token using the Authorization URL. Allow passing either the authorization code manually or the full URL in the configuration. Use a breakpoint to retrieve the refresh token and update the config file, streamlining the development process. - TradeStation example
-
Create brokerage config file in test project:
{ "brokerage-api-url": "api-url", "brokerage-app-key": "app-key", "brokerage-secret": "secret", "brokerage-authorization-code": "", "brokerage-refresh-token": "", "brokerage-redirect-url": "https://127.0.0.1" }
-
Create an independent class that manages the authentication process, ensuring it is solely responsible for authentication tasks. This class should be designed to function as middleware for our HTTP client in the future.
-
🧪 Unit test for the authentication process.
I recommend starting with the
GetHistory()
method, as it provides a clear understanding of the logic behind theSymbolMapper
as well.
- Implement
CanSubscribe()
- TradeStation example- Symbol must not be universe or canonical.;
- Brokerage must support the symbol's security type.
- Implement
GetHistory()
- TradeStation example- For each support Security Type;
- For each Resolution (which brokerage supports);
- Tick, Second, Minute, Hour, Daily
- For each TickType;
- Trade, Quote, OpenInterest
- Remarks:
- If the brokerage does not support a specific input parameter, it should log a warning immediately and return
null
from theGetHistory()
method. - Use different Consolidators to aggregate bar resolution.
- If the brokerage does not support a specific input parameter, it should log a warning immediately and return
- 🧪 Unit test:
GetHistory()
- TradeStation example- Create valid test cases for each combination of
Resolution
,TickType
,SecurityType
, and other relevant parameters; - Create invalid test cases to ensure the method returns
null
and no internal exceptions are thrown.
- Create valid test cases for each combination of
- Implement
GetBrokerageSymbol()
inclass SymbolMapper
- TradeStation example - 🧪 Unit test:
ReturnsCorrectBrokerageSymbol()
- TradeStation example- We pass Lean Symbol and get string of brokerage symbol
- Implement
GetCashBalance()
- TradeStation example - 🧪 Unit test:
GetCashBalance()
- We have generic method in
class BrokerageTests
- We have generic method in
- Implement
GetAccountHoldings()
- TradeStation example - 🧪 Unit test:
GetAccountHoldings()
- Note: skip doesn't support Security Types.
- Implement
GetOpenOrders()
- Binance example- All support OrderType;
- Convert brokerage order duration to Lean TimeInForce for each order;
- Note: skip doesn't support Security Types;
- Note: can create simple order with using brokerage Web UI or desktop app.
- Implement
GetLeanSymbol()
(Brokerage Ticker → Lean Symbol) - TradeStation example- Reuse existing conversion methods from the Lean source
- 🧪 Unit test:
GetLeanSymbol()
- TradeStation exampleReturnsCorrectLeanSymbol()
- Implement
PlaceOrder()
- Binance example, TradeStation example with CrossZeroOrder- Convert the Lean order type to the corresponding brokerage order type using specific parameters, then pass the request to the brokerage API.
- Add new BrokerageId to Lean.Order.BrokerId.
- Send the
new OrderEvent(...)
that the order was submitted successfully.
- 🧪 Unit test:
PlaceOrder()
- TradeStation example- different Security Types
- different MarketType (Market, Limit, Stop)
- Implement
CancelOrder()
- Bybit example- Validate that order has not cancelled or filled already to prevent from extra steps.
- Set up a continuous WebSocket connection.
- Implement
Connect()
- TradeStation examplepublic override bool IsConnected
- Returns true if the WebSocket is connected and the subscription to user/order updates is active.
- Implement
Disconnect()
- TradeStation example- Stop all WS subscription.
- Close connection.
- Implement User/Order update event. - Coinbase example
PlaceOrder()
and receive updates about it via WebSocket, sending the relevantOrderEvent
to Lean in real-time.- Note: We should synchronize the process to avoid race conditions. First, complete the
PlaceOrder
operation, then return the corresponding event. This means we need to pause new updates from the WebSocket until the order is fully processed.
- 🧪 Unit test:
PlaceOrder()
→ WS Update about filled. - Implement ReSubscribe to user update.
- When the internet connection is lost, we should initiate a new WebSocket connection.
- Implement
UpdateOrder()
- TradeStation example - 🧪 Unit test:
UpdateOrder()
- different Security Types.
- different quantities.
- different price.
- wrong price.
- wrong quantity.
- Implement the Subscription/Unsubscription process. (
interface IDataQueueHandler
)- subscribe on level one update (quotes, trades, openInterest)
- Remarks:
- Use
IDataAggregator
; - Use different
ExchangeTimeZone
to different symbols - TradeStation example; IDataAggregator.Update()
- different tick data.- use
DataQueueHandlerSubscriptionManager SubscriptionManager
fromabstract class BaseWebsocketsBrokerage
for Subscription/UnSubscription and count symbol, etc. - Use
class BrokerageMultiWebSocketSubscriptionManager
to multiple connection.
- Use
- 🧪 Unit test:
DataQueueHandler
- TradeStation example- Different Security Types;
- Different
SubscriptionDataConfig
(Resolution, TickType).
- Implement
ReSubscriptionProcess
- TradeStation example- When the internet connection is lost, we should establish a new stable connection and resubscribe to all the symbols that were previously subscribed to.
- Implement
IDataQueueUniverseProvider
- TradeStation example- option chain provider
- 🧪 Unit test:
IDataQueueUniverseProvider
- different symbol of the same security type (Option, IndexOption)
- Implement
Initialize()
to initialize brokerage only through one method. - TradeStation example - NOT FORGET:
ValidateSubscription()
- TradeStation example- place in
Initialize()
- The same in all brokerages.
- place in
- Implement
SetJob()
- TradeStation example- A brokerage can be started
IDataQueueHandler
and not as a brokerage.
- A brokerage can be started
- Implement
class BrokerageFactory
- TradeStation exampleDictionary<string, string> BrokerageData
- all brokerage configs.GetBrokerageModel(...)
- use it like reference to model in Lean.
- 🧪 Unit test:
BrokerageFactory
- Refactor:
brokerage.json
file in root of.sln
- Implement
gh-actions.yml
to great CI/CD.
Lean integration - TradeStation Lean PR
Use any Lean project as a reference within the brokerage integration to enhance debugging and streamline development.
- Fork Lean
- Implement
class BrokerageModel
- Support securities.
- Place and update orders.
- 🧪 Unit test:
BrokerageModel
- Added brokerage name in
BrokerageName.cs
- Added brokerage in
IBrokerageModel.cs
- Implement class
class BrokreageOrderProperties.cs
- different additional property for brokerage (e.g. support extend hours when place order)
- Implement
class BrokerageFeeModel
- Added config in
Launcher/config.json
Lean-CLI integration - CharlesSchwab Lean-CLI PR
- Fork lean-cli
- Upgrade
modules.json
- Update lean-cli Readmi file
python scripts/readme.py
- Re-Subscription Process (after internet disconnect)
- Re-subscribe to User/Order WebSocket Events;
- Re-subscribe to Market Data;
- Order Book;
- Trade Information;
- Level 1 Data.
- Multiple Subscriptions on Symbols
- Subscribe to Option Chains;
- Subscribe to Symbols with 500+;
- Subscribe to Symbols with 1.000+.
- Long-Running Test for Night and Weekend.
- Test Server Stability and Connection Resilience.
- Perform long-running tests during off-hours, such as nights and weekends, to validate that the remote server closes properly and that our connection remains stable.
- During this test, monitor the connection for unexpected disruptions or failures after the server shutdown.
- Test Server Stability and Connection Resilience.
- DON'T PUSH ANY CREDENTIALS IN THE COMMIT HISTORY.
- Each warning message in
GetHistory()
need log at once - TradeStation example - Use
OnMessage(...)
to display info to user- use different BrokerageMessageType
- example BrokerageMessageType.Warning
- example BrokerageMessageType.Error - stop algorithm in Lean.
- Use
OnOrderEvent(...)
to send any info about order.- use appropriate OrderStatus in it.
- example OnOrderEvent:OrderStatus.Submitted
- example OnOrderEvent:OrderStatus.UpdateSubmitted
- example OnOrderEvent:OrderStatus.Filled
- Not forget about OrderFee.
- To implement a RateGate that enforces brokerage restrictions.
- Use class BrokerageConcurrentMessageHandler to synchronize processes like
PlaceOrder()
/UpdateOrder()
/CancelOrder()
between brokerage and Lean.- we have lock getting new update with using
Monitor
underhood, example TradeStation.
- we have lock getting new update with using
- Use
IOrderProvider
to interact with actual Lean Order state in brokerage. - Avoid using
string
; prefer using Enums to reduce the number of bugs, example TradeStation Account Type. - Some brokerage need implement CrossZeroPositionOrder, reuse this logic.
- Inherit
class BaseWebsocketsBrokerage
insteadBrokerage
to reuse already implemented WebSocket interaction and overload specific method or use events. - Use
class BrokerageMultiWebSocketSubscriptionManager
to implement multiple WebSocket connect (if brokerage support)- example ByBit;
- write custom example TradeStation
- Use ExchangeTimeZone to specific Symbol to convert from UTC, example TradeStation.
- use DefaultOrderBook to keep High price in dictionary and emit new bid/ask price and size.
- example TradeStation
- use
lock(...){ }
block when you callIDataAggregator.Update()
. - Example of Re-Subscribe on Order updates - TradeStation
- Use
CancellationToken
; - Infinity loop;
- Small delay before requesting based on
CancellationToken
too. - If we will close connection,
CancellationToken
will be canceled and disposed well.
- Use