Python Virtual Environments / build (push) Has been cancelled
API Tests / build (push) Has been cancelled
Benchmarks / build (push) Has been cancelled
Build & Test Lean / build (push) Has been cancelled
Regression Tests / build (push) Has been cancelled
Report Generator Tests / build (push) Has been cancelled
Research Regression Tests / build (push) Has been cancelled
Syntax Tests / build (push) Has been cancelled
* Convert daily resolution market orders to MarketOnClose/MarketOnOpen
A market order placed intraday (e.g. through a scheduled event) on an
asset subscribed only at daily resolution has no fresh intraday price to
fill against, so it was filling at the stale previous daily close. This
is common when mixing daily resolution assets with minute resolution
assets or intraday scheduled events.
QCAlgorithm.MarketOrder now converts these orders so they fill at a real
daily open/close instead of the stale previous close:
- market closed (any resolution): MarketOnOpen, as before
- market open, daily-only subscription: MarketOnClose (today's close),
or MarketOnOpen (next open) when already within the MarketOnClose
submission buffer near the close
Assets with intraday data are left untouched, and the conversion is only
applied in backtesting; in live trading an open-market market order fills
at the real current price.
Adds DailyResolutionMarketOrderConversionRegressionAlgorithm covering the
MarketOnClose and MarketOnOpen conversion paths plus a minute resolution
asset that is correctly left as a regular market order.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* Minor fix
* Reword conversion warning: "current market price" instead of "real current price"
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* Update regression stats affected by daily market order conversion
Daily-resolution market orders placed intraday are now converted to
MarketOnClose/MarketOnOpen so they fill at a real daily open/close
instead of the stale previous close. This shifts the affected fills:
- IndexOptionCall{ITM,OTM}ExpiryDaily: the SPX option entry, placed one
minute after the open, now fills at the daily close. Same economics,
one extra data point and a new order list hash.
- AllShortableSymbols (C# + Python): an intraday order's type changed
from Market to a converted order; identical End Equity, new hash.
- ResolutionSwitchingAlgorithm sampling test: the RemoveSecurity
liquidation (fired at 15:50) previously filled at the stale previous
close; it now converts, shifting the equity/performance samples.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* Revert expected data point count change
---------
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Build & Test Lean / build (push) Has been cancelled
Regression Tests / build (push) Has been cancelled
Report Generator Tests / build (push) Has been cancelled
Research Regression Tests / build (push) Has been cancelled
Syntax Tests / build (push) Has been cancelled
Python Virtual Environments / build (push) Has been cancelled
* feature: add webull brokerage core integration
- add BrokerageName.Webull enum value
- add WebullBrokerageModel supporting Equity, Option, IndexOption
- add WebullFeeModel with zero commission for equity/option, tiered index option fees (SPX, SPXW, VIX/VIXW, XSP, DJX, NDX/NDXP), 0.6% crypto fee
- register Webull in IBrokerageModel factory switch and GetBrokerageName
- add webull config keys and live-webull environment to Launcher/config.json
- add WebullBrokerageModelTests (CanSubmitOrder, GetFeeModel)
- add WebullFeeModelTests covering all index option tiers and crypto
* refactor: split webull supported order types per security type
- replace flat _supportSecurityTypes/_supportOrderTypes with _supportedOrderTypesBySecurityType dictionary
- options and index options: Limit, StopMarket, StopLimit only
- equity, future, crypto: Market, Limit, StopMarket, StopLimit, TrailingStop
- add WebullOrderProperties with OutsideRegularTradingHours flag
- add messages for unsupported order type validation
* fix: add market order type to option and index option supported orders
* chore: add webull crypto symbols to symbol-properties-database
* test: consolidate webull fee model and brokerage model tests
- merge per-tier and per-symbol [Test] methods into [TestCase]/[TestCaseSource] parameterized tests in WebullFeeModelTests
- replace CreateIndexOptionSecurity/CreateOptionSecurity/CreateCryptoSecurity with single CreateSecurity(SecurityType, decimal, string) helper
- rename test methods to PascalCase (drop underscores) in WebullBrokerageModelTests
- remove section-separator comments from WebullBrokerageModelTests
- update Launcher/config.json for local Webull UAT environment
* remove: restriction GTC for Option and Buy side only
* refactor: limit webull to equity and options
- remove crypto and future support from order types and tests
- remove crypto fee logic and crypto symbol-properties rows
- reject market orders with outsideRth on equity
- log info when market order uses non-day tif
Regression Tests / build (push) Has been cancelled
Report Generator Tests / build (push) Has been cancelled
Research Regression Tests / build (push) Has been cancelled
Syntax Tests / build (push) Has been cancelled
Python Virtual Environments / build (push) Has been cancelled
API Tests / build (push) Has been cancelled
Benchmarks / build (push) Has been cancelled
Build & Test Lean / build (push) Has been cancelled
Add LocateBroker (string) and LocateId (string) so algorithms can attach
Reg SHO locate information to short equity sales routed through Bloomberg
EMSX. These map to the EMSX_LOCATE_BROKER and EMSX_LOCATE_ID fields on the
EMSX order ticket (LocBrkr / LocId). The TerminalLink brokerage emits
EMSX_LOCATE_REQ = "Y" automatically whenever either identifier is set on
a short equity sale, so no separate "required" flag is exposed here.
Without these properties the TerminalLink brokerage has no way to identify
the lender on a short sale, and prime brokers reject the order.
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Build & Test Lean / build (push) Has been cancelled
Regression Tests / build (push) Has been cancelled
Report Generator Tests / build (push) Has been cancelled
Research Regression Tests / build (push) Has been cancelled
Syntax Tests / build (push) Has been cancelled
Python Virtual Environments / build (push) Has been cancelled
* Add VIX Mini Futures (VXM) support
Adds complete LEAN support for VIX Mini Futures (VXM) traded on CBOE:
- Add Futures.Indices.VIXMini = "VXM" constant
- Add expiry function: 30 days before third Friday of following month
- Add symbol properties: multiplier 100, tick 0.01 (USD)
- Add 15 test date pairs for 2023-2025 to FuturesExpiryFunctionsTestData.xml
- Add [TestCase(VIXMini, EightOClockChicagoTime)] to IndicesExpiryDateFunction test
- Add market hours configuration mirroring VX trading hours
ClosesQuantConnect/Lean#6655
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
* Fix VXM expiry holiday validation and add margin file
- Replace single `if` holiday check with `while` loop using
`IsCommonBusinessDay()` to ensure the computed expiry date
is always a valid tradable day (not just one step back)
- Fix test data: 2025-03-19 -> 2025-03-18 (April 18 2025 is
Good Friday, a CFE holiday, shifting the expiry back)
- Add Data/future/cfe/margins/VXM.csv margin file
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Claude Haiku 4.5 <noreply@anthropic.com>
Build & Test Lean / build (push) Has been cancelled
Regression Tests / build (push) Has been cancelled
Report Generator Tests / build (push) Has been cancelled
Research Regression Tests / build (push) Has been cancelled
Syntax Tests / build (push) Has been cancelled
Python Virtual Environments / build (push) Has been cancelled
- add saleCondition/exchange overload to UpdateQuote
- normalize exchange via GetPrimaryExchange in UpdateQuote/UpdateLastTrade
- cover exchange mapping with combined test
* Fix SessionConsolidator skipping daily bars on manual Update
* Fix SessionConsolidator bar timestamp when no data arrives for a trading day
* Address review comments
* Minor fix
* Move initialization logic to start of AggregateBar
* Throw clear error when AddData is called with a non-class first argument from Python
Calls like self.add_data("VIX", Resolution.DAILY) routed through CreateType, which
silently built a dynamic assembly named after the string and returned a fake type
whose activator factory tried to invoke the str like a function. The downstream
'str' object is not callable PythonException surfaced confusingly (and could
manifest as an apparent hang depending on where it was caught), making the actual
mistake hard to diagnose.
Validate the PyObject up front via TryCreateType in the AddData(PyObject, ...)
entry points and throw an ArgumentException pointing the user at AddEquity /
AddForex / etc. when the argument is not a custom data class.
* Improve the error message
Use only two alternative methods as examples, as we don't need an exhaustive list.
Regression Tests / build (push) Has been cancelled
Report Generator Tests / build (push) Has been cancelled
Research Regression Tests / build (push) Has been cancelled
Syntax Tests / build (push) Has been cancelled
Python Virtual Environments / build (push) Has been cancelled
API Tests / build (push) Has been cancelled
Benchmarks / build (push) Has been cancelled
Build & Test Lean / build (push) Has been cancelled
* Default to all market hours when no symbol is provided
Add no-symbol overloads of `AfterMarketOpen`, `BeforeMarketOpen`,
`AfterMarketClose` and `BeforeMarketClose` so scheduled events can be
defined without referencing a specific security. Per-date, the helpers
pick the earliest open / latest close across the algorithm's
non-always-open exchanges, falling back to US equities (SPY) when no
eligible security is subscribed. US equities are skipped during the
walk since SPY's exchange hours already represent them.
Closes#9461.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* Test that option contracts dedupe to one exchange hours entry
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* Allow SetAccountCurrency after SetCash without throwing
Previously, calling SetAccountCurrency after SetCash threw an
InvalidOperationException. The portfolio manager now switches the
base account currency in place: the previous Cash entry (and its
balance) is preserved in the CashBook, and a notice is logged. When
the new account currency matches the existing one, an optional
startingCash overrides the previously set amount and the override
is logged.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* Simplify SetAccountCurrency remarks and drop unused message
Tightens the XML remarks to two cases (different currency: keep previous
in its own entry; matching currency: override). Also removes the now
unused CannotChangeAccountCurrencyAfterSettingCash string since the
portfolio no longer throws.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* Simplify in-line comment in SetAccountCurrency
Drops the "Undo that migration" wording (residue from a previous fix
attempt) and just describes what the branch does: keep the previous
balance in its own currency entry while the new account currency starts
at zero.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* Differentiate implicit vs explicit SetCash on account currency switch
SetCash(decimal) is currency-agnostic: the amount is "this many units of
the (eventual) account currency". Switching the account currency now
re-labels the amount onto the new currency instead of preserving the
previous one. SetCash(symbol, ...) for the current account currency keeps
the old behaviour of preserving the balance in its own CashBook entry.
Splits the existing tests by overload and adds a starting-cash variant
for the explicit case.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* Mark base cash explicit on any SetCash(symbol, ...) call
Broaden _baseCashSymbolSetExplicitly so any call to the explicit-currency
overload signals the user is committing to named currencies, not just
calls whose symbol matches the current account currency. SetAccountCurrency
then preserves the previous base-currency balance in its own CashBook
entry whenever the user has touched the explicit overload at all.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Implement WaveTrendOscillator (bar indicator) per the linked issue. Adds
the indicator class, the WTO helper in QCAlgorithm.Indicators.cs, unit
tests inheriting CommonIndicatorTests<IBaseDataBar>, and the reference
CSV under Tests/TestData/.
The oscillator is computed from the typical price (HLC/3): an EMA
smooths it (ESA), a second EMA tracks its absolute deviation (D), the
normalized channel index (HLC3 - ESA) / (0.015 * D) is smoothed by a
third EMA to produce WT1, and an SMA of WT1 produces the signal line
WT2. Crossovers between WT1 and WT2 are commonly used as entry and exit
signals for momentum reversals.
Reference values were generated with TA-Lib (talib.EMA + talib.SMA)
following the script posted by @LouisSzeto in the issue thread.
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Regression Tests / build (push) Has been cancelled
Report Generator Tests / build (push) Has been cancelled
Research Regression Tests / build (push) Has been cancelled
Python Virtual Environments / build (push) Has been cancelled
API Tests / build (push) Has been cancelled
Syntax Tests / build (push) Has been cancelled
Build & Test Lean / build (push) Has been cancelled
* fix: add AJY future-option expiry definition
- map AJY (AUD/JPY) FOP to SecondFridayBeforeThirdWednesdayOfContractMonth
- prior fallback to the AJY HMUZ-only future expiry collapsed serial-month FOPs (e.g. AJYN6) into their underlying quarterly Symbol
* fix: add ANE and ECD future-option expiry definitions
- map ANE (AUD/NZD) and ECD (EUR/CAD) FOPs to SecondFridayBeforeThirdWednesdayOfContractMonth
- prior fallback to the HMUZ-only future expiry collapsed serial-month FOPs into their underlying quarterly Symbol
Build & Test Lean / build (push) Has been cancelled
Regression Tests / build (push) Has been cancelled
Report Generator Tests / build (push) Has been cancelled
Research Regression Tests / build (push) Has been cancelled
Syntax Tests / build (push) Has been cancelled
Python Virtual Environments / build (push) Has been cancelled
* feature: add NASDAQ_SC and NASDAQ_INT equity exchanges
- map primary exchange codes S and T to new NASDAQ tier exchanges
- T was previously folded into NASDAQ, now returns NASDAQ_INT
- add V as alias for IEX in equity switch
- fix MEMX description (was copy of LTSE)
* feature: map equity exchange codes H and U to MIAX_PEARL and MEMX
* feature: consolidate NASDAQ_INT code T into NASDAQ_SC
Remove the separate NASDAQ_INT mapping in GetPrimaryExchange and map
exchange code "T" to NASDAQ_SC. Update ExchangeTest cases accordingly
and add coverage for IEX ("V") and MEMX ("U").
* feature: remove orphaned NASDAQ_INT exchange entry
Drop the NASDAQ_INT class entry from Exchange.cs. The "T" tape letter
already routes to Exchange.NASDAQ via GetPrimaryExchange, leaving the
class definition unreachable and inconsistent.
* fix: support BNFCR alternative collateral in CryptoFutureMarginModel for Binance (#9339)
* refactor: use classic switch in BinanceFuturesBrokerageModel.GetBuyingPowerModel
* fix: CryptoFutureMarginModel in BinanceCoinFuturesBrokerageModel
* refactor: simplify BinanceCryptoFutureMarginModel collateral conversion
* fix: restore IsCryptoCoinFuture guard in BinanceCryptoFutureMarginModel
* refactor: simplify BinanceCryptoFutureMarginModel to direct BNFCR lookup
Replace IsStableCoinWithoutPair foreach loop with a single TryGetValue
check for BNFCR. BNFCR is EU/EEA-only (MiCA Credits Trading Mode) so
the lookup is a no-op for all other users. Amount reflects availableBalance
from the Binance API — the total cross-margin pool already aggregated by
Binance — making the > 0 guard correct and avoiding CashBook iteration.
* feat: add regression algorithm for BNFCR as sole collateral on Binance USDⓈ-M futures
Asserts end-to-end that EU/MiCA accounts with zero USDT and BNFCR as
the only collateral can open ADAUSDT positions. Verifies buying power,
holdings AbsoluteHoldingsCost, TotalSaleVolume, TotalMarginUsed,
maintenance margin consistency and TotalUnrealizedProfit accuracy.
* refactor: BNFCR presence gate with CashBook iteration for supplementary collateral
Replace IsStableCoinWithoutPair and hardcoded asset list with CashBook
iteration gated by BNFCR presence. Binance controls which assets are in
the account — all with non-zero walletBalance are valid collateral.
Add tests for BNFCR zero balance and BTC collateral conversion.
* refactor: aggregate all collateral without reference equality check
* fix: shared collateral deduction across quote currencies for EU/MiCA BNFCR mode
- Extract virtual SharesCollateral in CryptoFutureMarginModel
- Override in BinanceCryptoFutureMarginModel: BNFCR present → all USDⓈ-M share pool
- Add BNFCRCurrency const
- Add SharedCollateralDeductsMaintenanceMarginAcrossQuoteCurrencies unit test
- Refactor regression algorithm to assert shared collateral across ADAUSDT/ETHUSDC
* refactor: remove dead IsCryptoCoinFuture guard from BinanceCryptoFutureMarginModel
- Remove IsCryptoCoinFuture() check (coin futures use BinanceCoinFuturesBrokerageModel, not this model)
- Call base.GetTotalCollateralAmount() instead of duplicating primaryCollateral.Amount
- Remove CoinFutureDoesNotIncludeBnfcrAsCollateral test (tested wrong margin model)
* refactor: make GetCollateralCash private in CryptoFutureMarginModel
- No longer accessed by subclasses after removing direct collateral checks from BinanceCryptoFutureMarginModel
Previously, each SwissArmyKnife instance could only compute a single
tool. To use multiple tools, users had to create separate instances.
Now all five tools (Gauss, Butter, HighPass, TwoPoleHighPass, BandPass)
are computed simultaneously and exposed as public properties.
Resolves#3270
Build & Test Lean / build (push) Has been cancelled
Regression Tests / build (push) Has been cancelled
API Tests / build (push) Has been cancelled
Benchmarks / build (push) Has been cancelled
Report Generator Tests / build (push) Has been cancelled
Research Regression Tests / build (push) Has been cancelled
Syntax Tests / build (push) Has been cancelled
Python Virtual Environments / build (push) Has been cancelled
* Improves Null Key Handling in Python
We aim to mimic the following behavior:
```python
>>> d = {1:2}
>>> None in d
False
>>> d.get(None) is None
True
>>> d.pop(None)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
KeyError: None
>>> d.pop(None, None) is None
True
```
* Reverts dispose change
Build & Test Lean / build (push) Has been cancelled
Regression Tests / build (push) Has been cancelled
Report Generator Tests / build (push) Has been cancelled
Research Regression Tests / build (push) Has been cancelled
Syntax Tests / build (push) Has been cancelled
Python Virtual Environments / build (push) Has been cancelled
* Add ContractMultiplier setter to Cfd via CfdSymbolProperties
* Fix regression tests
* Solve review comments
* Address new review comments
* Fix regression tests
* Use ContractSymbolProperties as base class
* Minor fix
* Address review comment
* Add failing test for BRK.B OSI option ticker parsing
Adds test case to ParseOptionTickerOSI to reproduce issue #9341 where
Symbol.ParseOptionTickerOSI throws on tickers containing a dot (e.g. BRK.B).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* Fix OSI option ticker regex to support dots in underlying symbol
Extends _optionTickerRegex from [A-Z0-9]+ to [A-Z0-9\.]+ so that
symbols like BRK.B are accepted by ParseOptionTickerOSI.
Fixes#9341
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Python Virtual Environments / build (push) Has been cancelled
Benchmarks / build (push) Has been cancelled
Build & Test Lean / build (push) Has been cancelled
Regression Tests / build (push) Has been cancelled
Research Regression Tests / build (push) Has been cancelled
Syntax Tests / build (push) Has been cancelled
Report Generator Tests / build (push) Has been cancelled
API Tests / build (push) Has been cancelled
* feat: add CreateOAuthTokenHandler factory to Brokerage base class
Introduce AuthenticationFailed event on TokenHandler raised when all
retry attempts are exhausted. Add CreateOAuthTokenHandler<TRequest,TResponse>
protected factory method on Brokerage that wires the event to OnMessage
(BrokerageMessageType.Error), triggering graceful Lean shutdown on
OAuth token refresh failure without requiring per-brokerage error logic.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* refactor: token retry logic: move to OAuthTokenHandler
* refactor: replace generic OAuthTokenHandler with non-generic, require explicit token lifetime
- Remove generic type parameters <TRequest, TResponse> from OAuthTokenHandler and
CreateOAuthTokenHandler; use LeanAccessTokenMetaDataRequest and
AccessTokenMetaDataResponse directly
- Delete abstract AccessTokenMetaDataRequest; logic moved to LeanAccessTokenMetaDataRequest
- Make tokenLifetime a required constructor parameter — each brokerage must explicitly
declare its OAuth token lifetime to prevent silent 1-hour fallback bugs
- Move expiry tracking into the handler via _tokenExpiresAt (written under lock before the
volatile write of _tokenCredentials, ensuring correct visibility on the fast path)
- Simplify AccessTokenMetaDataResponse to a concrete class with { get; set; } properties
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* test: add unit tests for OAuthTokenHandler and AccessTokenMetaDataResponse
- Make ApiConnection.TryRequest<T>(HttpRequestMessage) virtual to allow
test subclasses to intercept without real HTTP calls
- Add AccessTokenMetaDataResponseTests: two parameterized cases verify that
TokenType defaults to Bearer when absent from JSON (CharlesSchwab pattern)
and deserializes correctly when present (Tastytrade pattern)
- Add OAuthTokenHandlerTests with FakeApiConnection stub:
CharlesSchwab-style response (no tokenType, 30-min lifetime) and
Tastytrade-style response (explicit tokenType + expiresIn/tokenId, 15-min lifetime)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* refactor: backward-compatible OAuth auth with new LeanOAuthTokenHandler hierarchy
- Restore master API: OAuthTokenHandler<TReq,TRes>, AccessTokenMetaDataRequest,
AccessTokenMetaDataResponse, and TokenHandler stay source-compatible for old consumers
- Extend TokenHandler with AuthenticationFailed event; simplify Send() (auth header only)
- Add LeanOAuthTokenHandler: non-generic, thread-safe double-checked locking, explicit
tokenLifetime, retry logic in GetAccessToken, fires AuthenticationFailed on exhaustion
- Add OAuthTokenRequest / OAuthTokenResponse: concrete Lean platform request/response
- Brokerage.CreateOAuthTokenHandler wires AuthenticationFailed to graceful shutdown
- Update tests: OAuthTokenResponseTests, LeanOAuthTokenHandlerTests, TokenHandlerTests
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* Some tweaks
---------
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-authored-by: Martin Molinero <martin.molinero1@gmail.com>
* Use universe settings when adding derivatives
Use resolution, fill forward and extended market hours settings from universe settings when adding derivative securities (options, index options, futures and future options)
* Minor python syntax check fix
* Minor change
* Default resolution from universe settings for common lean types securities
* Minor test fix
* Cleanup
* Use consolidated bar as reference for new working bar initialization
* Update ValidateAndScan method and unit tests
* Fix issues with syntax check
* Solve review comments
* Minor fix
* Minor fix
Report Generator Tests / build (push) Has been cancelled
Research Regression Tests / build (push) Has been cancelled
Syntax Tests / build (push) Has been cancelled
Benchmarks / build (push) Has been cancelled
Build & Test Lean / build (push) Has been cancelled
Regression Tests / build (push) Has been cancelled
Python Virtual Environments / build (push) Has been cancelled
* Fix: Reject unsupported 4-leg ComboLegLimit orders in InteractiveBrokersBrokerageModel (#9287)
* Minor tweaks
---------
Co-authored-by: Ahmed Ali <ahmedalli79x@gmail.com>
Co-authored-by: Martin Molinero <martin.molinero1@gmail.com>
* feat: add CanonicalDataDownloaderDecorator for chain support
Introduced CanonicalDataDownloaderDecorator to enable automatic resolution and parallel downloading of all contracts for canonical symbols (options and futures chains). Updated Program.cs and DownloaderDataProvider to use this decorator, ensuring seamless data retrieval for both canonical and non-canonical symbols. Refactored initialization logic to handle chain providers within the decorator and removed redundant code from Program.cs.
* feat: improve canonical symbol error handling in data downloader
* refactor: data downloader selection in DownloaderDataProvider
* refactor: CanonicalDataDownloaderDecorator construction
* feat: limit parallelism and improve contract data error handling
* refactor: canonical data downloader and provider usage
* remove: CanonicalNotSupportedException and refactor handling
* refactor: data downloader selection with selector class
Introduce DataDownloaderSelector to choose the correct IDataDownloader implementation based on data type, using CanonicalDataDownloaderDecorator only when needed. Update Program.cs and DownloaderDataProvider to use the selector, remove redundant initialization logic, and ensure proper resource disposal. This improves flexibility, correctness, and resource management for data downloads, especially for custom and canonical data types.
* fix: wrong selector condition
* refactor: change default log handler; add parallelism config to downloader
- Set ConsoleLogHandler as the default log handler in code and config
- Make contract download parallelism configurable via downloader-thread-count (default 4)
- Track and log number of processed contracts in CanonicalDataDownloaderDecorator
- Add error logging for missing universe data
- Improve logging clarity and code readability
* feat: prevent duplicate contract downloads in canonical chains
Introduce ContractDownloadParameters to uniquely identify contract/tick type/resolution combinations and cache them in CanonicalDataDownloaderDecorator, avoiding redundant downloads when contracts are shared across canonical symbol chains. Add date range optimization for contract downloads and unit tests for the new class.
* Revert "feat: prevent duplicate contract downloads in canonical chains"
This reverts commit 44386c4c788904531c473c60c2a173e2354561ec.
* feat: clamp contract date ranges, deduplicate downloads
Added AdjustDateRangeForContract to CanonicalDataDownloaderDecorator to clamp start/end dates based on contract expiry and security type. Introduced _contractsCache to prevent duplicate downloads across canonical chains and _processedContracts for logging. Updated contract retrieval logic for deduplication. Added NUnit tests to verify date range adjustments for futures and options.
* refactor: canonical contract date range adjustment logic
* test:feat: add test for non-option/future contract date adjustment
* feat: make look-back periods for canonical symbols configurable
* refactor: remove Lazy from CanonicalDataDownloaderDecorator
Revert "refactor: remove Lazy from CanonicalDataDownloaderDecorator"
This reverts commit 909c1299406688a19352273f8d0b5b3ea99c0fb9.
refactor: Inject IMapFileProvider into downloader selectors
Revert "refactor: Inject IMapFileProvider into downloader selectors"
This reverts commit 0add95269809680e425bfa6080e465bf16377e56.
Reapply "refactor: remove Lazy from CanonicalDataDownloaderDecorator"
This reverts commit 9e3c4bed078868a3c8dfedcab0e52d6dced1daad.
* refactor: data downloader dependency injection
* refactor: provider initialization in data downloader classes
* refactor: DataDownloaderSelector dependencies, add tests
- Require explicit IDataProvider in DataDownloaderSelector constructor, removing default and fallback logic
- Change default log handler to ConsoleLogHandler in Program.cs
- Pass DownloaderDataProvider as IDataProvider to DataDownloaderSelector
- Add DataDownloaderSelector unit tests to verify correct downloader selection and decorator usage
* feat: ensure factorFileProvider is initialized when defaulted
* fix: missed dataProvider in DataDownloaderSelector ctor
* refactor: improve IFactorFileProvider resolution in DataDownloaderSelector