Compare commits

..

80 Commits
17385 ... 17477

Author SHA1 Message Date
Jhonathan Abreu
26584c2fd0 Stop and delete unused threads in tests (#9219) 2026-01-13 13:13:37 -03:00
Roman Yavnikov
48fd4eccff Feat: override ToString() in several Event Args (#9217)
* feat: override ToString() in several Event Args

* fix: typo
2026-01-13 10:00:48 -03:00
JosueNina
75d5cbcf2a Fix: RandomDataGenerator crashes when algorithm is null (#9211)
* Fix NullReferenceException in SecurityService

* Simplify the unit test

* Add unit test for RandomDataGenerator

* Improve unit test name

* Solve review comments
2026-01-12 14:50:01 -04:00
Jhonathan Abreu
d702587ad8 Fix SecurityIdentifier properties lazy initialization (#9214) 2026-01-09 18:07:26 -03:00
Jhonathan Abreu
c99a9dab32 Update CNH future quote currency (#9213) 2026-01-09 15:44:29 -03:00
JosueNina
8196d0b557 HistoryRequest parameters now defaults to the security configuration (#9209)
* Fix HistoryRequest DataMappingMode default to use security configuration

* Solve review comments

* Make HistoryRequest inherit existing subscription configuration values generically

* Exclude any class that inherits from BaseChainUniverseData

* Reuse existing filter for user configuration

* Solve review comments

* Normalize DataMappingMode

* Minor fix
2026-01-09 15:43:46 -03:00
Ricardo Andrés Marino Rojas
3ee941f329 Remove wrong holidays in MHDB (#9205)
Remove wrong holidays in CME group Dairy, Livestock and Lumber products.
There was also a wrong holidays in Future-cbot-KE
2026-01-07 16:13:28 -03:00
Ricardo Andrés Marino Rojas
286353b763 Remove duplicated dates (#9207) 2026-01-07 16:13:19 -03:00
Ricardo Andrés Marino Rojas
d5f298c235 Add missing Oanda, SGX and Cfd-InteractiveBrokers 2026 holidays to MHDB (#9204)
* Add 2026 Oanda holidays

* Add 2026 new year holiday SGX

* Add Cfd-interactivebrokers 2026 holidays

* Remove wrong holidays in Forex-oanda-[*]

* Nit change
2026-01-07 13:08:40 -03:00
Ricardo Andrés Marino Rojas
f2c5551b1e Remove dates present in generic entry Index-usa and others (#9202) 2026-01-06 17:19:07 -03:00
Ricardo Andrés Marino Rojas
f86a51ac3f Remove dates in generic Interactive Brokers entry part 10 (#9201)
* Remove dates present in IB generic entry part 9

* Remove dates in IB generic entry part 10
2026-01-06 16:14:25 -03:00
Ricardo Andrés Marino Rojas
1253cc73bd Remove dates present in IB generic entry part 9 (#9200) 2026-01-06 16:12:19 -03:00
Ricardo Andrés Marino Rojas
6506ff53a3 Remove dates in generic Interactive Brokers entry part 8 (#9199)
* Remove dates present in IB generic entry part 7

* Remove dates present in IB generic entry part 8
2026-01-06 14:32:01 -03:00
Ricardo Andrés Marino Rojas
713785157e Remove dates present in IB generic entry part 7 (#9198) 2026-01-06 14:30:07 -03:00
Ricardo Andrés Marino Rojas
fd7048d2d1 Remove dates present in IB generic entry part 6 (#9197) 2026-01-06 13:27:45 -03:00
Ricardo Andrés Marino Rojas
1b66aeede1 Remove dates present in IB generic entry part 5 (#9196) 2026-01-06 13:10:04 -03:00
Ricardo Andrés Marino Rojas
2f80a2a6b9 Remove dates in generic Interactive Brokers entry part 4 (#9193)
* Remove dates present in generic entries

* Remove dates present in IB generic entry
2026-01-06 12:45:59 -03:00
Ricardo Andrés Marino Rojas
68d4da8e76 Remove dates present in generic entries (#9192) 2026-01-06 12:22:20 -03:00
Ricardo Andrés Marino Rojas
538405d152 Remove dates present in generic interactivebrokers (#9191) 2026-01-06 11:59:37 -03:00
Ricardo Andrés Marino Rojas
1f3fd6edbb Reduce (part of) dates already present in generic entries from MHDB (#9190)
* Remove dates present in cme generic entry

* Remove dates present in cbot generic entry

* Remove dates present in nymex generic entry

* Remove dates present in comex generic entry

* Remove dates present in oanda generic entry

* Remove dates present in SGX and HKFE generic entries
2026-01-06 11:52:15 -03:00
Adalyat Nazirov
e3783ed477 Override GetBuyingPowerModel to support USDC collaterla in dYdX brokerage (#9187) 2026-01-05 09:55:46 -03:00
Ricardo Andrés Marino Rojas
1171e4fe52 Add 2026 Future EUREX, CFE and ICE Holidays (#9183)
* rebase Add 2026 EUREX, CFE and ICE Holidays

* Remove entries present in generic entry

For some ICE Future entries, there were holidays that were already
present in their generic entry (Future-ice-[*]), so those dates were
removed from the entry
2026-01-02 16:05:36 -03:00
Martin-Molinero
a66f279852 Fix some incorrect future expirations (#9184)
- Some future expiry functions were missing to account for holidays,
  adding unit test reproducing issue
2026-01-02 12:58:29 -03:00
Martin-Molinero
6575b57146 Fix future expiration year calculation (#9182) 2026-01-02 10:21:02 -03:00
yyxxddjj
3fa700e450 New Feature: Implement Covariance Indicator #6982 (#9144)
* Implements Covariance as Lean Indicator

* Add COV helper method and fix AcceptsVolumeRenkoBarsAsInput test

* Fix AcceptsRenkoBarsAsInput test to use smaller period for faster execution

* Fix slow Renko tests by limiting data processed to 50 rows
2025-12-31 16:02:03 -03:00
Adalyat Nazirov
7735917c83 Prioritize CryptoFuture data feeds for dYdX (#9178)
* Prioritize CryptoFuture data feeds for dYdX

* revert changes for existing crypto subscriptions

* use Concat instead of adding into list
2025-12-31 13:19:58 -03:00
Jhonathan Abreu
67489eef57 Add GetInt64 StreamReader extension method (#9177)
* Add GetInt64 StreamReader extension method

* Minor change

* Cleanup

* Add unit tests
2025-12-31 11:58:51 -04:00
JosueNina
241306275a Replace external dataset with mock data in sweetviz test (#9176) 2025-12-31 12:18:22 -03:00
Ricardo Andrés Marino Rojas
773bd53525 Add 2026 CME Future & HKFE Holidays, early closes, late opens and bank holidays (#9174)
* Add 2026 HKFE Future holidays & early closes

* rebase Add 2026 Future-cme-equity Holidays, Early closes, late opens

* Add (again) HKFE 2026 Holidays and early closes

* Add Future-cme-interest 2026 holidays

* Add 2026 CME Fx 2026 holidays"

- Add 2026 CME Fx holidays, early closes, late opens, bank holidays
- Exclude CNH, MNH and MIR as they expire rules don't consider US
  Holidays
- Fix wrong early close on 12/24/2025 from 12:15 to 12:45

* Add CME Future crypto 2026 Holidays, EC, LO & BH

* Add CME Future Energy 2026 holidays, EC, LO, BH

* Add CME Futures metals holidays, ec, lo, bh

* Add CME Futures grains 2026 holidays, ec, lo, bh

* Add CME Futures Dairy 2026 holidays, ec, lo, bh

* Add CME Futures livestock holidays, ec, lo, bh

* Add CME Future Lumber holidays, ec, lo, bh

* Add CME Futures Softs holidays, ec, lo, bh

* Add CME Futures Oilseeds holidays, ec, lo, bh

* Add CME Futures AW, GD Holidays, EC, LO and BH

* Move repeated bank holidays to generic entries

* Nit change

* Solve bug

Since 11/26/2026 is a bank holiday for CME energy futures, the expiry
date is moved to 11/25/2026 as the expiry date for HH is the third last
business day of the month prior to the contract month
2025-12-31 11:33:59 -03:00
JosueNina
0854ab82da Default option filter now includes weeklies to prevent empty chains (#9162)
* Return weekly contracts if no standard contracts exist

* Fix unit and regression tests

* Centralize default expiration type flags

* Add ExcludeWeeklys() method

* Mark IncludeWeeklys() as obsolete since weeklies are now default
2025-12-31 10:11:46 -03:00
JosueNina
2c0390fde3 Change Config.Get logging from Trace to Debug level (#9171)
* Change Config.Get logs from Trace to Debug level to reduce noise

* Wrap Config.Get logs with DebuggingEnabled check
2025-12-31 10:09:37 -03:00
JosueNina
32fcd94abc Exclude Period property from WindowIndicator (#9172) 2025-12-31 10:08:37 -03:00
Martin-Molinero
090ffebd03 Minor ApiConnection improvement (#9173) 2025-12-30 18:48:27 -03:00
JosueNina
914d0810af Make Collaborator.Uid nullable to fix JSON deserialization error (#9170) 2025-12-30 15:40:22 -03:00
Martin-Molinero
10902f95dd net10 fix: Update clr-loader (#9166) 2025-12-29 19:07:35 -03:00
Martin-Molinero
2e67b9ad4f Feature net10 update (#9161)
* Feature update to net10

* Update to net10

* Update pythonnet to 2.0.51

* Remove dotnet config

* Remove net9

* Minor cleanup
2025-12-29 09:53:37 -03:00
Ricardo Andrés Marino Rojas
7adf27aa61 Add 2026 CME Future Holidays, EC, LP, BH (#9163)
- Add 2026 CME Future Holidays, Early closes, Late opens and bank holidays
- Exclude MIR, CNH, MNH as they expire rules don't follow US holidays
2025-12-27 10:52:23 -03:00
Martin-Molinero
7ea0f60905 Add SGX futures holidays (#9160) 2025-12-26 15:24:55 -03:00
Martin-Molinero
d9c71e3d34 Adding Forex-Oanda & Cfd-IB 2026 new years holiday. Removing duplication (#9159) 2025-12-26 12:10:19 -03:00
Martin-Molinero
b040518d52 Minor foundation update reverts (#9156) 2025-12-24 17:02:49 -03:00
Roman Yavnikov
725737610a fix: several Futures Currencies: 6B, 6M, 6J, 6E, 6C (#9155) 2025-12-24 17:39:50 +02:00
Martin-Molinero
37ccee4937 Update foundation image (#9154) 2025-12-24 11:17:50 -03:00
Jhonathan Abreu
0ab0abd1ca Clean up after removing RestSharp (#9153) 2025-12-23 13:45:31 -03:00
Jhonathan Abreu
c565f4cfd0 Refactor optimization statistics serialization (#8984)
* Refactor optimization result stats serialization

* Handle custom optimization statistics serialization

* Support custom statistics

* Support newest Lean statistics

Address peer review

* Add more tests

* Make indices reserved statistic names

* Minor fixes and cleanup
2025-12-22 17:08:24 -04:00
Ricardo Andrés Marino Rojas
f804b8f0ca Add 2026 Index holidays to MHDB (#9152)
* Add index-usa-[*] holidays and early closes

* Add Index-spx 2026-2027 holidays & early closes

* Add 2026 Index-ndx holidays & early closes

* Add 2026 Index-VIX holidays and early closes

* Add EUREX Index holidays 2026-2030

* Add index HKFE 2026 holidays and early closes

* Add 2026 Index-OSE holidays and early closes

* Add missing 2026 Index-India NSE holidays

* Address suggested changes
2025-12-22 16:42:25 -03:00
Jhonathan Abreu
ef1cf8e4df Replace RestShap with HttpClient (#9143)
* Replace RestShap with HttpClient

* Address peer review

* Minor fixes
2025-12-22 09:50:25 -04:00
Ricardo Andrés Marino Rojas
661356e33e Add missing USA equity holidays and early closes (#9148)
* Add 2025-2027 USA equity holidays

* Address reviews
2025-12-19 17:18:42 -03:00
Martin-Molinero
5842f50b03 Trigger initial selection for a yearly schedule (#9149)
- Trigger initial selection for a yearly scheduled universe. Adding
  regression algorithm.
2025-12-19 16:45:37 -03:00
Martin-Molinero
0f80591f51 Fix null reference un future contract. Adding tests (#9147) 2025-12-19 13:51:45 -03:00
JosueNina
0622f43a0f Fix issues with the IchimokuKinkoHyo indicator (#9135)
* Fix issues with IchimokuKinkoHyo indicator

* Use indicator extension methods for automatic updates
2025-12-19 12:48:49 -03:00
JosueNina
8f0224feb6 Fix StopLimit validation bug (#9142) 2025-12-19 12:35:19 -03:00
Jhonathan Abreu
781897984e Detect serialized json payload in CreateJsonPostRequest (#9145) 2025-12-19 11:24:03 -04:00
Roman Yavnikov
340b40c6ce Fix: AUD(6A) FOP expiration (#9139)
* fix: AUD(6A) FOP expiration

* feat: add 6A to FOP expiry delta
refactor: rename variable to project pattern naming

* remove: AUD fop expiry delta
test:fix: use flexible reference data in  FutureAndOptionMapping

* test:fix: AUD in GetUnderlyingSymbolFromFutureOption
2025-12-19 15:52:06 +02:00
Jhonathan Abreu
58ce899b5d Add Api helper methods for POST requests (#9134)
* Add Api helper methods for POST requests

* Support json serializer setting for json requests

* Minor changes and cleanup

* Make ApiConnection disposable
2025-12-16 18:08:28 -04:00
Martin Nemček
ead8335c84 #8356 Implemention of NHNL indicators (#9109)
* #8356 Implemented NHNL indicators

* #8356 Formatting cleanup

* #8356 Review changes

* #8356 use of var

* #8356 Refactoring of tests classes

---------

Co-authored-by: Martin Nemček <nemcek@metaapp.sk>
2025-12-16 14:24:00 -03:00
Aibek Minbaev
84ee81b35b Feat 8909 add python env support in report generation (#9128)
* Added python-venv to ReportArgumentParser, getting python-venv in Program class

* Added venv activation and python initialization to Report class

* Resolve review comments. Move python init and env addition to Report/Program.cs
2025-12-16 13:42:23 -03:00
JosueNina
03be232f31 Fix issues with IgnoresInsightsWithInvalidMagnitudeValue tests (#9131) 2025-12-15 18:24:11 -03:00
Martin-Molinero
e568162bff Minor slice.AllData api change (#9130) 2025-12-15 10:25:00 -03:00
Derek Melchin
e395892b8e Fix camelCase constructor args (#9127) 2025-12-11 15:15:17 -03:00
Jared
3483fee766 Remove debug message for daily precise end time (#9126)
Removed debug message regarding daily precise end times.
2025-12-11 15:14:22 -03:00
Jhonathan Abreu
6cba915950 Fix minor bug with restsharp auth header (#9125)
* Fix minor bug with restsharp auth header

* Minor fix
2025-12-11 15:13:37 -03:00
Martin-Molinero
046df38be8 Fix log timestamp & minor cleanup (#9124) 2025-12-11 13:44:30 -03:00
Jhonathan Abreu
c7e96b837d Minor fix for json to stream serialization extension (#9123) 2025-12-10 18:29:57 -04:00
Martin-Molinero
2f23c89307 Avoid FF enumerator error warning (#9122) 2025-12-10 18:18:08 -03:00
Jhonathan Abreu
67d19d88d7 Add ApiConnection constructor for backwards compatibility (#9121) 2025-12-10 16:16:38 -04:00
Jhonathan Abreu
b4401db512 Refactor ApiClient to use HttpClient (#9114)
* Refactor ApiClient to use HttpClient

* Minor fix

* Refactor and cleanup in ApiConnection

* Add normalized extension methods for string and stream json serialization

* Minor fixes

* Address peer review

* Minor fixes

* Minor fixes and peer review

* Race condition fix

* Minor changes

* Cleanup

* Minor fixes

* Minor fix
2025-12-10 15:40:46 -04:00
Jhonathan Abreu
bc646c974a Use proper extended dictionary types for public properties (#9119) 2025-12-09 13:01:29 -03:00
Adalyat Nazirov
857a950e23 dYdX Brokerage Essentials (#9116)
* add dYdX market constant

* Add dYdX market constant and update symbol properties database

* get Gaz limit from order properties or default value

* wip

* add symbol properties

* add more dydx order props

* update symbol properties

* Add dYdX brokerage and fee model

* Update dYdX configuration fields

* undone meta files

* minor tweaks

* fix file ending

* Add dYdX brokerage support to BrokerageName and IBrokerageModel

* Refine dYdX fee model integration and update configuration defaults

* Replace custom order size validation in dYdXBrokerageModel with DefaultBrokerageModel implementation

* undone changes

* Add market hours for dYdX CryptoFuture
2025-12-09 09:58:06 -03:00
JosueNina
888752fa0a Avoid unnecessary Python wrapper creation for pure C# models (#9106)
* Centralize Python/C# model detection logic

* Improve helper method

* Remove unnecessary conditionals

* Fix unit tests

* Refactor QCAlgorithm.python.cs to use the new helper method for models

* Solve review comments

* Clean up Python wrapper exception

* Update XML comments to better describe T and TWrapper in CreateModelOrWrapper

* Join unit tests in TestCases

* Solve review comments

* Replace manual TryConvert checks with CreateInstanceOrWrapper helper
2025-12-08 18:01:31 -03:00
Martin-Molinero
14427129c7 Minor fix to handle all tick security updates (#9117) 2025-12-08 17:41:28 -03:00
Jhonathan Abreu
683bfe007a Avoid emitting overlapping fill forwarded data (#9107)
* Avoid emitting overlapping fill forward data

* Cleanup
2025-12-05 10:05:40 -04:00
Jhonathan Abreu
263a9099ed Add TryDownloadData extension method (#9111) 2025-12-05 10:03:27 -04:00
JosueNina
a78004a1e6 Add default values to ConstantAlphaModel (#9104)
* Initial solution

* Add unit tests

* Fix constructor parameter mismatch in ConstantAlphaModel

* Delete unused constructor
2025-12-01 13:49:17 -03:00
Jhonathan Abreu
9acd30c355 Make DataDictionary ordered by key (symbol) (#9105)
* Make DataDictionary ordered by key (symbol)

* Cache DataDictionary sorted items

* Minor tests fixes

* Minor changes

* Minor changes
2025-12-01 12:44:22 -04:00
JosueNina
441ba1a7b5 Add ExtendedDictionary implementations (#9096)
* Add ExtendedDictionary implementations

- Add DefaultExtendedDictionary<TKey, TValue> class
- Add ReadOnlyExtendedDictionary<TKey, TValue> class
- Refactor exposed dictionaries

* Make DataDictionary inherits from DefaultExtendedDictionary

* Refactor UniverseManager

* Return ReadOnlyExtendedDictionary in GetParameters()

* Solve review comments

* Remove unnecesary property, no longer required

* Reduce code duplication

* Solve new review comments

* Remove unnecesary constraints

* Replace BaseExtendedDictionary with DataDictionary in GetLastKnownPrices method

* Remove unused extensions
2025-11-28 16:03:02 -04:00
JosueNina
52b788d9de Fix inclusive loop upper bound (#9102) 2025-11-28 12:39:09 -04:00
Jhonathan Abreu
16fdf61903 Track securities addition and removal notifications (#9097)
* Track security addition and removal sent notifications

* Minor regression algorithm fixes

* Fix regression algorithms data points count

* Add description to new regression algorithms

* Simplify tracking removal notifications

* Cleanup
2025-11-28 10:37:31 -04:00
Roman Yavnikov
59990573c2 Fix: Use decimal option strike precision (#9099)
* fix: use decimal instead long in Scale's LeanData
test:feat: validate naming with large precision

* feat: use normalization in Scale's LeanData
test:fix: strike precisions

* fix: use str normalization in Scale's LeanData
2025-11-25 20:32:06 +02:00
yyxxddjj
acb787e8f6 Docs(Algorithm): Add XML code references (#9077)
* Docs(Algorithm): Add XML code references

Adds XML documentation tags (<see/>, <paramref/>) to code
references within the Algorithm folder. This improves code
navigation, IntelliSense, and helps the stubs generator tool
to correctly map C# elements.

Resolves #9016

* Fix missing newline at end of QCAlgorithm.cs

* Update print statement from 'Hello' to 'Goodbye'

* Fix documentation for market parameter in crypto methods
2025-11-24 17:51:42 -04:00
JosueNina
6260b2f7e0 Replace /// with <summary> (#9095) 2025-11-24 17:09:39 -04:00
257 changed files with 27935 additions and 42226 deletions

View File

@@ -28,9 +28,9 @@ jobs:
shell: bash
run: |
# install dependencies
pip3 install papermill==2.4.0 clr-loader==0.1.6
pip3 install papermill==2.4.0 clr-loader==0.2.9
# install kernel
dotnet tool install --global Microsoft.dotnet-interactive --version 1.0.607001
dotnet tool install -g --no-cache --version 1.0.661703 --add-source "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-tools/nuget/v3/index.json" Microsoft.dotnet-interactive
# Add dotnet tools to Path
export PATH="$HOME/.dotnet/tools:$PATH"
# activate kernel for jupyter

View File

@@ -115,7 +115,7 @@ namespace QuantConnect.Algorithm.CSharp
/// <summary>
/// Data Points count of all timeslices of algorithm
/// </summary>
public long DataPoints => 62;
public long DataPoints => 61;
/// <summary>
/// Data Points count of the algorithm history
@@ -132,34 +132,34 @@ namespace QuantConnect.Algorithm.CSharp
/// </summary>
public Dictionary<string, string> ExpectedStatistics => new Dictionary<string, string>
{
{"Total Orders", "3"},
{"Total Orders", "4"},
{"Average Win", "0%"},
{"Average Loss", "-0.03%"},
{"Compounding Annual Return", "-2.594%"},
{"Drawdown", "0.000%"},
{"Average Loss", "-0.10%"},
{"Compounding Annual Return", "-14.232%"},
{"Drawdown", "0.200%"},
{"Expectancy", "-1"},
{"Start Equity", "100000"},
{"End Equity", "99966.4"},
{"Net Profit", "-0.034%"},
{"Sharpe Ratio", "-10.666"},
{"End Equity", "99803.9"},
{"Net Profit", "-0.196%"},
{"Sharpe Ratio", "-7.95"},
{"Sortino Ratio", "0"},
{"Probabilistic Sharpe Ratio", "1.216%"},
{"Loss Rate", "100%"},
{"Win Rate", "0%"},
{"Profit-Loss Ratio", "0"},
{"Alpha", "-0.029"},
{"Beta", "0.004"},
{"Annual Standard Deviation", "0.003"},
{"Alpha", "-0.128"},
{"Beta", "0.026"},
{"Annual Standard Deviation", "0.016"},
{"Annual Variance", "0"},
{"Information Ratio", "-0.768"},
{"Tracking Error", "0.241"},
{"Treynor Ratio", "-6.368"},
{"Information Ratio", "-1.186"},
{"Tracking Error", "0.237"},
{"Treynor Ratio", "-4.747"},
{"Total Fees", "$8.60"},
{"Estimated Strategy Capacity", "$5500000.00"},
{"Lowest Capacity Asset", "ES VMKLFZIH2MTD"},
{"Portfolio Turnover", "66.80%"},
{"Estimated Strategy Capacity", "$2000.00"},
{"Lowest Capacity Asset", "ES VU1EHIDJYLMP"},
{"Portfolio Turnover", "66.50%"},
{"Drawdown Recovery", "0"},
{"OrderListHash", "39f1e15c27212d8fdd58aeb7fb2b93cc"}
{"OrderListHash", "4720516462fcabb4db1aead46051cb4a"}
};
}
}

View File

@@ -137,7 +137,7 @@ namespace QuantConnect.Algorithm.CSharp
{"Lowest Capacity Asset", "ES 31C3JQS9DCF1G|ES XCZJLC9NOB29"},
{"Portfolio Turnover", "495.15%"},
{"Drawdown Recovery", "0"},
{"OrderListHash", "3f6016b4879428eaef0b7057d4b86f18"}
{"OrderListHash", "af830085995d0b8fa0d33a6e80dd1241"}
};
}
}

View File

@@ -240,31 +240,31 @@ namespace QuantConnect.Algorithm.CSharp
{"Total Orders", "2"},
{"Average Win", "0%"},
{"Average Loss", "0%"},
{"Compounding Annual Return", "309.669%"},
{"Drawdown", "0.900%"},
{"Compounding Annual Return", "430.834%"},
{"Drawdown", "4.200%"},
{"Expectancy", "0"},
{"Start Equity", "100000"},
{"End Equity", "101950.53"},
{"Net Profit", "1.951%"},
{"Sharpe Ratio", "15.402"},
{"End Equity", "102313.03"},
{"Net Profit", "2.313%"},
{"Sharpe Ratio", "17.721"},
{"Sortino Ratio", "0"},
{"Probabilistic Sharpe Ratio", "95.977%"},
{"Loss Rate", "0%"},
{"Win Rate", "0%"},
{"Profit-Loss Ratio", "0"},
{"Alpha", "1.886"},
{"Beta", "1.066"},
{"Annual Standard Deviation", "0.155"},
{"Annual Variance", "0.024"},
{"Information Ratio", "13.528"},
{"Tracking Error", "0.142"},
{"Treynor Ratio", "2.237"},
{"Alpha", "2.663"},
{"Beta", "1.264"},
{"Annual Standard Deviation", "0.184"},
{"Annual Variance", "0.034"},
{"Information Ratio", "16.514"},
{"Tracking Error", "0.169"},
{"Treynor Ratio", "2.574"},
{"Total Fees", "$3.57"},
{"Estimated Strategy Capacity", "$760000.00"},
{"Lowest Capacity Asset", "ES XCZJLDQX7338|ES XCZJLC9NOB29"},
{"Portfolio Turnover", "32.31%"},
{"Estimated Strategy Capacity", "$28000000.00"},
{"Lowest Capacity Asset", "ES XCZJLCA62LNO|ES XCZJLC9NOB29"},
{"Portfolio Turnover", "33.84%"},
{"Drawdown Recovery", "0"},
{"OrderListHash", "9179c6e6a693a6593c97bfa825d53170"}
{"OrderListHash", "7c82013ecabca41591e0253a477025dd"}
};
}
}

View File

@@ -96,7 +96,7 @@ namespace QuantConnect.Algorithm.CSharp
/// <summary>
/// Data Points count of all timeslices of algorithm
/// </summary>
public long DataPoints => 1658168;
public long DataPoints => 2349547;
/// <summary>
/// Data Points count of the algorithm history

View File

@@ -38,7 +38,7 @@ namespace QuantConnect.Algorithm.CSharp
SetEndDate(2013, 10, 10);
var SP500 = QuantConnect.Symbol.Create(Futures.Indices.SP500EMini, SecurityType.Future, Market.CME);
_symbol = FuturesChain(SP500).First();
_symbol = FuturesChain(SP500).OrderBy(x => x.Symbol.ID.Date).First();
// Test case: custom IndicatorBase<QuoteBar> indicator using Future unsubscribed symbol
var indicator1 = new CustomIndicator();

View File

@@ -127,7 +127,7 @@ namespace QuantConnect.Algorithm.CSharp
/// <summary>
/// Data Points count of all timeslices of algorithm
/// </summary>
public virtual long DataPoints => 5861;
public virtual long DataPoints => 5867;
/// <summary>
/// Data Points count of the algorithm history
@@ -144,34 +144,34 @@ namespace QuantConnect.Algorithm.CSharp
/// </summary>
public virtual Dictionary<string, string> ExpectedStatistics => new Dictionary<string, string>
{
{"Total Orders", "34"},
{"Total Orders", "38"},
{"Average Win", "0.33%"},
{"Average Loss", "-0.04%"},
{"Compounding Annual Return", "0.106%"},
{"Average Loss", "-0.03%"},
{"Compounding Annual Return", "0.098%"},
{"Drawdown", "0.300%"},
{"Expectancy", "0.178"},
{"Expectancy", "0.165"},
{"Start Equity", "1000000"},
{"End Equity", "1001066.2"},
{"Net Profit", "0.107%"},
{"Sharpe Ratio", "-1.695"},
{"Sortino Ratio", "-0.804"},
{"Probabilistic Sharpe Ratio", "14.797%"},
{"Loss Rate", "88%"},
{"Win Rate", "12%"},
{"Profit-Loss Ratio", "9.01"},
{"End Equity", "1000991.96"},
{"Net Profit", "0.099%"},
{"Sharpe Ratio", "-1.708"},
{"Sortino Ratio", "-0.84"},
{"Probabilistic Sharpe Ratio", "14.542%"},
{"Loss Rate", "89%"},
{"Win Rate", "11%"},
{"Profit-Loss Ratio", "10.07"},
{"Alpha", "-0.007"},
{"Beta", "0.002"},
{"Annual Standard Deviation", "0.004"},
{"Annual Variance", "0"},
{"Information Ratio", "-1.353"},
{"Information Ratio", "-1.354"},
{"Tracking Error", "0.089"},
{"Treynor Ratio", "-4.112"},
{"Total Fees", "$76.30"},
{"Treynor Ratio", "-4.054"},
{"Total Fees", "$85.54"},
{"Estimated Strategy Capacity", "$0"},
{"Lowest Capacity Asset", "ES VRJST036ZY0X"},
{"Portfolio Turnover", "0.92%"},
{"Portfolio Turnover", "1.04%"},
{"Drawdown Recovery", "69"},
{"OrderListHash", "ddaa9dd20647fdbc4811d6e64bb30a40"}
{"OrderListHash", "eafc33ea4dcb219f7aacdbdd0973d5bc"}
};
}
}

View File

@@ -36,7 +36,7 @@ namespace QuantConnect.Algorithm.CSharp
/// <summary>
/// Data Points count of all timeslices of algorithm
/// </summary>
public override long DataPoints => 25312;
public override long DataPoints => 25339;
/// <summary>
/// This is used by the regression test system to indicate what the expected statistics are from running the algorithm
@@ -70,7 +70,7 @@ namespace QuantConnect.Algorithm.CSharp
{"Lowest Capacity Asset", "ES VP274HSU1AF5"},
{"Portfolio Turnover", "20.14%"},
{"Drawdown Recovery", "0"},
{"OrderListHash", "f6482c8757f82cb9f4c058e3ed6bc494"}
{"OrderListHash", "c301a0a086f8905b1a555f0257087272"}
};
}
}

View File

@@ -36,41 +36,41 @@ namespace QuantConnect.Algorithm.CSharp
/// <summary>
/// Data Points count of all timeslices of algorithm
/// </summary>
public override long DataPoints => 5965;
public override long DataPoints => 5971;
/// <summary>
/// This is used by the regression test system to indicate what the expected statistics are from running the algorithm
/// </summary>
public override Dictionary<string, string> ExpectedStatistics => new Dictionary<string, string>
{
{"Total Orders", "32"},
{"Total Orders", "36"},
{"Average Win", "0.33%"},
{"Average Loss", "-0.04%"},
{"Compounding Annual Return", "0.110%"},
{"Average Loss", "-0.03%"},
{"Compounding Annual Return", "0.103%"},
{"Drawdown", "0.300%"},
{"Expectancy", "0.184"},
{"Expectancy", "0.172"},
{"Start Equity", "1000000"},
{"End Equity", "1001108"},
{"Net Profit", "0.111%"},
{"Sharpe Ratio", "-1.688"},
{"Sortino Ratio", "-0.772"},
{"Probabilistic Sharpe Ratio", "14.944%"},
{"Loss Rate", "88%"},
{"Win Rate", "12%"},
{"Profit-Loss Ratio", "8.47"},
{"End Equity", "1001033.76"},
{"Net Profit", "0.103%"},
{"Sharpe Ratio", "-1.701"},
{"Sortino Ratio", "-0.809"},
{"Probabilistic Sharpe Ratio", "14.685%"},
{"Loss Rate", "89%"},
{"Win Rate", "11%"},
{"Profit-Loss Ratio", "9.55"},
{"Alpha", "-0.007"},
{"Beta", "0.002"},
{"Annual Standard Deviation", "0.004"},
{"Annual Variance", "0"},
{"Information Ratio", "-1.353"},
{"Tracking Error", "0.089"},
{"Treynor Ratio", "-4.099"},
{"Total Fees", "$72.00"},
{"Treynor Ratio", "-4.042"},
{"Total Fees", "$81.24"},
{"Estimated Strategy Capacity", "$0"},
{"Lowest Capacity Asset", "ES VRJST036ZY0X"},
{"Portfolio Turnover", "0.87%"},
{"Portfolio Turnover", "0.99%"},
{"Drawdown Recovery", "69"},
{"OrderListHash", "741a26424d2210171ad849d92fc75d23"}
{"OrderListHash", "67120ad5c9a6116001dda6c8061e5353"}
};
}
}

View File

@@ -41,7 +41,7 @@ namespace QuantConnect.Algorithm.CSharp
/// <summary>
/// Data Points count of all timeslices of algorithm
/// </summary>
public override long DataPoints => 67924;
public override long DataPoints => 67998;
/// <summary>
/// This is used by the regression test system to indicate what the expected statistics are from running the algorithm

View File

@@ -44,7 +44,7 @@ namespace QuantConnect.Algorithm.CSharp
_optionSymbol = option.Symbol;
// set our strike/expiry filter for this option chain
option.SetFilter(u => u.Strikes(-2, +2)
option.SetFilter(u => u.StandardsOnly().Strikes(-2, +2)
// Expiration method accepts TimeSpan objects or integer for days.
// The following statements yield the same filtering criteria
.Expiration(0, 180));
@@ -73,7 +73,7 @@ namespace QuantConnect.Algorithm.CSharp
var higherStrike = callContracts[2].Strike;
var optionStrategy = OptionStrategies.CallButterfly(_optionSymbol, higherStrike, middleStrike, lowerStrike, expiry);
Order(optionStrategy, 10);
}
}

View File

@@ -50,8 +50,9 @@ namespace QuantConnect.Algorithm.CSharp
// set our strike/expiry filter for this option chain
// SetFilter method accepts TimeSpan objects or integer for days.
// The following statements yield the same filtering criteria
option.SetFilter(-2, +2, 0, 180);
// option.SetFilter(-2, +2, TimeSpan.Zero, TimeSpan.FromDays(180));
option.SetFilter(u => u.StandardsOnly()
.Strikes(-2, +2)
.Expiration(0, 180));
// Adding this to reproduce GH issue #2314
SetWarmup(TimeSpan.FromMinutes(1));
@@ -83,7 +84,7 @@ namespace QuantConnect.Algorithm.CSharp
Liquidate();
}
foreach(var kpv in slice.Bars)
foreach (var kpv in slice.Bars)
{
Log($"---> OnData: {Time}, {kpv.Key.Value}, {kpv.Value.Close:0.00}");
}

View File

@@ -48,11 +48,10 @@ namespace QuantConnect.Algorithm.CSharp
_optionSymbol = option.Symbol;
// set our strike/expiry filter for this option chain
option.SetFilter(u => u.Strikes(-2, +2)
option.SetFilter(u => u.StandardsOnly().Strikes(-2, +2)
// Expiration method accepts TimeSpan objects or integer for days.
// The following statements yield the same filtering criteria
.Expiration(0, 180));
// .Expiration(TimeSpan.Zero, TimeSpan.FromDays(180)));
.Expiration(0, 180)); // .Expiration(TimeSpan.Zero, TimeSpan.FromDays(180)));
// use the underlying equity as the benchmark
SetBenchmark(equity.Symbol);

View File

@@ -48,7 +48,7 @@ namespace QuantConnect.Algorithm.CSharp
_optionSymbol = option.Symbol;
// set our strike/expiry filter for this option chain
option.SetFilter(u => u.Strikes(-2, +2)
option.SetFilter(u => u.StandardsOnly().Strikes(-2, +2)
// Expiration method accepts TimeSpan objects or integer for days.
// The following statements yield the same filtering criteria
.Expiration(0, 180));

View File

@@ -58,7 +58,7 @@ namespace QuantConnect.Algorithm.CSharp
var option = AddOption(equity.Symbol, fillForward: true);
_optionSymbol = option.Symbol;
option.SetFilter(u => u.Strikes(-2, +2)
option.SetFilter(u => u.StandardsOnly().Strikes(-2, +2)
.Expiration(0, 180));
}

View File

@@ -47,7 +47,7 @@ namespace QuantConnect.Algorithm.CSharp
var option = AddOption(equity.Symbol, fillForward: true);
_optionSymbol = option.Symbol;
option.SetFilter(u => u.Strikes(-2, +2)
option.SetFilter(u => u.StandardsOnly().Strikes(-2, +2)
.Expiration(0, 180));
}
@@ -243,8 +243,7 @@ namespace QuantConnect.Algorithm.CSharp
}
if (orderEvent.Quantity != order.Quantity)
{
throw new RegressionTestException($@"OrderEvent quantity should hold the current order Quantity. Got {orderEvent.Quantity
}, expected {order.Quantity}");
throw new RegressionTestException($@"OrderEvent quantity should hold the current order Quantity. Got {orderEvent.Quantity}, expected {order.Quantity}");
}
if (order is ComboLegLimitOrder && orderEvent.LimitPrice == 0)
{
@@ -303,8 +302,7 @@ namespace QuantConnect.Algorithm.CSharp
{
throw new RegressionTestException(
"There were expected 6 filled market orders, 3 filled combo limit orders and 6 filled combo leg limit orders, " +
$@"but there were {filledComboMarketOrders.Count} filled market orders, {filledComboLimitOrders.Count
} filled combo limit orders and {filledComboLegLimitOrders.Count} filled combo leg limit orders");
$@"but there were {filledComboMarketOrders.Count} filled market orders, {filledComboLimitOrders.Count} filled combo limit orders and {filledComboLegLimitOrders.Count} filled combo leg limit orders");
}
if (openOrders.Count != 0 || openOrderTickets.Count != 0)

View File

@@ -47,7 +47,7 @@ namespace QuantConnect.Algorithm.CSharp
SetEndDate(2020, 01, 20);
var SP500 = QuantConnect.Symbol.Create(Futures.Indices.SP500EMini, SecurityType.Future, Market.CME);
var symbol = FuturesChain(SP500).First();
var symbol = FuturesChain(SP500).OrderBy(x => x.Symbol.ID.Date).First();
_future = AddFutureContract(symbol);
var tradableDatesCount = QuantConnect.Time.EachTradeableDayInTimeZone(_future.Exchange.Hours,

View File

@@ -43,7 +43,7 @@ namespace QuantConnect.Algorithm.CSharp
var option = AddOption(equity.Symbol);
_optionSymbol = option.Symbol;
option.SetFilter(u => u.Strikes(-1, +1).Expiration(0, 30));
option.SetFilter(u => u.StandardsOnly().Strikes(-1, +1).Expiration(0, 30));
}
/// <summary>
/// OnData event is the primary entry point for your algorithm. Each new data point will be pumped in here.
@@ -70,7 +70,7 @@ namespace QuantConnect.Algorithm.CSharp
var legs = new List<Leg> { Leg.Create(atmContract.Symbol, -1), Leg.Create(atmContract.Symbol.Underlying, 100) };
var comboPrice = underlyingPrice - optionPrice;
if(comboPrice < 734m)
if (comboPrice < 734m)
{
// just to make sure the price makes sense
throw new RegressionTestException($"Unexpected combo price {comboPrice}");

View File

@@ -40,7 +40,7 @@ namespace QuantConnect.Algorithm.CSharp
SetEndDate(2014, 07, 06);
var option = AddOption("AAPL", Resolution.Daily);
option.SetFilter(-5, +5, 0, 365);
option.SetFilter(u => u.StandardsOnly().Strikes(-5, +5).Expiration(0, 365));
_symbol = option.Symbol;
}

View File

@@ -62,7 +62,7 @@ namespace QuantConnect.Algorithm.CSharp
/// <summary>
/// Data Points count of all timeslices of algorithm
/// </summary>
public long DataPoints => 70735;
public long DataPoints => 70736;
/// <summary>
/// Data Points count of the algorithm history

View File

@@ -0,0 +1,76 @@
/*
* 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.Collections.Generic;
using QuantConnect.Securities;
namespace QuantConnect.Algorithm.CSharp
{
/// <summary>
/// Regression algorithm asserting that a future contract selected by both the continuous future and
/// the future chain universes gets liquidated on delisting and that the algorithm receives the correct
/// security addition/removal notifications.
///
/// This algorithm uses Gold futures with midnight expiry time to reproduce an edge case where
/// the delisting data instance and the universe deselection happen in the same loop but without a particular order.
///
/// This partly reproduces GH issue https://github.com/QuantConnect/Lean/issues/9092
/// </summary>
public class DelistedFutureLiquidateFromChainAndContinuousMidnightExpiryRegressionAlgorithm : DelistedFutureLiquidateFromChainAndContinuousRegressionAlgorithm
{
protected override string FutureTicker => Futures.Metals.Gold;
/// <summary>
/// Data Points count of all timeslices of algorithm
/// </summary>
public override long DataPoints => 317492;
/// <summary>
/// This is used by the regression test system to indicate what the expected statistics are from running the algorithm
/// </summary>
public override Dictionary<string, string> ExpectedStatistics => new Dictionary<string, string>
{
{"Total Orders", "2"},
{"Average Win", "0%"},
{"Average Loss", "-5.18%"},
{"Compounding Annual Return", "-20.700%"},
{"Drawdown", "6.400%"},
{"Expectancy", "-1"},
{"Start Equity", "100000"},
{"End Equity", "94817.53"},
{"Net Profit", "-5.182%"},
{"Sharpe Ratio", "-2.965"},
{"Sortino Ratio", "-3.407"},
{"Probabilistic Sharpe Ratio", "0.000%"},
{"Loss Rate", "100%"},
{"Win Rate", "0%"},
{"Profit-Loss Ratio", "0"},
{"Alpha", "-0.064"},
{"Beta", "-0.2"},
{"Annual Standard Deviation", "0.048"},
{"Annual Variance", "0.002"},
{"Information Ratio", "-4.899"},
{"Tracking Error", "0.11"},
{"Treynor Ratio", "0.716"},
{"Total Fees", "$2.47"},
{"Estimated Strategy Capacity", "$1400000.00"},
{"Lowest Capacity Asset", "GC VL5E74HP3EE5"},
{"Portfolio Turnover", "3.18%"},
{"Drawdown Recovery", "0"},
{"OrderListHash", "c197fe000cd6d7f2fd84860f7086d730"}
};
}
}

View File

@@ -0,0 +1,196 @@
/*
* 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.Collections.Generic;
using System.Linq;
using QuantConnect.Data;
using QuantConnect.Data.UniverseSelection;
using QuantConnect.Interfaces;
using QuantConnect.Orders;
using QuantConnect.Securities;
using QuantConnect.Securities.Future;
namespace QuantConnect.Algorithm.CSharp
{
/// <summary>
/// Regression algorithm asserting that a future contract selected by both the continuous future and
/// the future chain universes gets liquidated on delisting and that the algorithm receives the correct
/// security addition/removal notifications.
///
/// This partly reproduces GH issue https://github.com/QuantConnect/Lean/issues/9092
/// </summary>
public class DelistedFutureLiquidateFromChainAndContinuousRegressionAlgorithm : QCAlgorithm, IRegressionAlgorithmDefinition
{
private Symbol _contractSymbol;
private Future _continuousFuture;
private DateTime _internalContractRemovalTime;
private DateTime _contractRemovalTime;
protected virtual string FutureTicker => Futures.Indices.SP500EMini;
public override void Initialize()
{
SetStartDate(2013, 10, 08);
SetEndDate(2013, 12, 30);
_continuousFuture = AddFuture(FutureTicker);
_continuousFuture.SetFilter(0, 182);
}
public override void OnData(Slice slice)
{
if (_contractSymbol == null)
{
foreach (var chain in slice.FutureChains)
{
// Make sure the mapped contract is in the chain, that is, is selected by both universes
if (chain.Value.Any(x => x.Symbol == _continuousFuture.Mapped))
{
_contractSymbol = _continuousFuture.Mapped;
var ticket = MarketOrder(_contractSymbol, 1);
if (ticket.Status != OrderStatus.Filled)
{
throw new RegressionTestException($"Order should be filled: {ticket}");
}
}
}
}
}
public override void OnSecuritiesChanged(SecurityChanges changes)
{
if (changes.RemovedSecurities.Any(x => x.Symbol == _contractSymbol))
{
if (_contractRemovalTime != default)
{
throw new RegressionTestException($"Contract {_contractSymbol} was removed multiple times");
}
_contractRemovalTime = Time;
}
else
{
changes.FilterInternalSecurities = false;
if (changes.RemovedSecurities.Any(x => x.Symbol == _contractSymbol))
{
if (_internalContractRemovalTime != default)
{
throw new RegressionTestException($"Contract {_contractSymbol} was removed multiple times as internal subscription");
}
_internalContractRemovalTime = Time;
}
}
}
public override void OnEndOfAlgorithm()
{
if (_contractSymbol == null)
{
throw new RegressionTestException("No contract was ever traded");
}
if (_internalContractRemovalTime == default)
{
throw new RegressionTestException($"Contract {_contractSymbol} was not removed from the algorithm");
}
if (_contractRemovalTime == default)
{
throw new RegressionTestException($"Contract {_contractSymbol} was not removed from the algorithm as external subscription");
}
// The internal subscription should be removed first (on continuous future mapping),
// and the regular subscription later (on delisting)
if (_contractRemovalTime < _internalContractRemovalTime)
{
throw new RegressionTestException($"Contract {_contractSymbol} was removed from the algorithm as aregular subscription before internal subscription");
}
if (Securities[_contractSymbol].Invested)
{
throw new RegressionTestException($"Position should be closed when {_contractSymbol} got delisted {_contractSymbol.ID.Date}");
}
}
public override void OnOrderEvent(OrderEvent orderEvent)
{
Log($"{orderEvent}. Delisting on: {_contractSymbol.ID.Date}");
}
/// <summary>
/// This is used by the regression test system to indicate if the open source Lean repository has the required data to run this algorithm.
/// </summary>
public bool CanRunLocally { get; } = true;
/// <summary>
/// This is used by the regression test system to indicate which languages this algorithm is written in.
/// </summary>
public List<Language> Languages { get; } = new() { Language.CSharp };
/// <summary>
/// Data Points count of all timeslices of algorithm
/// </summary>
public virtual long DataPoints => 288140;
/// <summary>
/// Data Points count of the algorithm history
/// </summary>
public int AlgorithmHistoryDataPoints => 0;
/// <summary>
/// Final status of the algorithm
/// </summary>
public AlgorithmStatus AlgorithmStatus => AlgorithmStatus.Completed;
/// <summary>
/// This is used by the regression test system to indicate what the expected statistics are from running the algorithm
/// </summary>
public virtual Dictionary<string, string> ExpectedStatistics => new Dictionary<string, string>
{
{"Total Orders", "2"},
{"Average Win", "7.02%"},
{"Average Loss", "0%"},
{"Compounding Annual Return", "34.386%"},
{"Drawdown", "1.500%"},
{"Expectancy", "0"},
{"Start Equity", "100000"},
{"End Equity", "107016.6"},
{"Net Profit", "7.017%"},
{"Sharpe Ratio", "3.217"},
{"Sortino Ratio", "0"},
{"Probabilistic Sharpe Ratio", "99.828%"},
{"Loss Rate", "0%"},
{"Win Rate", "100%"},
{"Profit-Loss Ratio", "0"},
{"Alpha", "0.228"},
{"Beta", "0.108"},
{"Annual Standard Deviation", "0.084"},
{"Annual Variance", "0.007"},
{"Information Ratio", "-1.122"},
{"Tracking Error", "0.112"},
{"Treynor Ratio", "2.501"},
{"Total Fees", "$2.15"},
{"Estimated Strategy Capacity", "$1700000000.00"},
{"Lowest Capacity Asset", "ES VMKLFZIH2MTD"},
{"Portfolio Turnover", "2.01%"},
{"Drawdown Recovery", "16"},
{"OrderListHash", "640ce720644ff0b580687e80105d0a92"}
};
}
}

View File

@@ -18,6 +18,7 @@ using System;
using System.Collections.Generic;
using System.Linq;
using QuantConnect.Data;
using QuantConnect.Data.UniverseSelection;
using QuantConnect.Interfaces;
using QuantConnect.Orders;
using QuantConnect.Securities;
@@ -30,6 +31,7 @@ namespace QuantConnect.Algorithm.CSharp
public class DelistedFutureLiquidateRegressionAlgorithm : QCAlgorithm, IRegressionAlgorithmDefinition
{
private Symbol _contractSymbol;
private bool _contractRemoved;
protected virtual Resolution Resolution => Resolution.Minute;
/// <summary>
@@ -65,8 +67,21 @@ namespace QuantConnect.Algorithm.CSharp
}
}
public override void OnSecuritiesChanged(SecurityChanges changes)
{
if (changes.RemovedSecurities.Any(x => x.Symbol == _contractSymbol))
{
_contractRemoved = true;
}
}
public override void OnEndOfAlgorithm()
{
if (!_contractRemoved)
{
throw new RegressionTestException($"Contract {_contractSymbol} was not removed from the algorithm");
}
Log($"{_contractSymbol}: {Securities[_contractSymbol].Invested}");
if (Securities[_contractSymbol].Invested)
{

View File

@@ -146,10 +146,10 @@ namespace QuantConnect.Algorithm.CSharp
{"Treynor Ratio", "-15.266"},
{"Total Fees", "$11.36"},
{"Estimated Strategy Capacity", "$65000000.00"},
{"Lowest Capacity Asset", "ES XCZJLDQX7338|ES XCZJLC9NOB29"},
{"Lowest Capacity Asset", "ES XCZJLDQR8R1G|ES XCZJLC9NOB29"},
{"Portfolio Turnover", "0.16%"},
{"Drawdown Recovery", "0"},
{"OrderListHash", "48b7918176ec22534969502849fe596b"}
{"OrderListHash", "f9210adc1afc4460146528006675e734"}
};
}
}

View File

@@ -125,7 +125,7 @@ namespace QuantConnect.Algorithm.CSharp
{"Lowest Capacity Asset", "IBM R735QTJ8XC9X"},
{"Portfolio Turnover", "39.89%"},
{"Drawdown Recovery", "0"},
{"OrderListHash", "32f56b0f4e9300ef1a34464e8083c7e7"}
{"OrderListHash", "d2af4746a4d01ca4d0ce0b0c44f30451"}
};
}
}

View File

@@ -160,33 +160,33 @@ namespace QuantConnect.Algorithm.CSharp
public Dictionary<string, string> ExpectedStatistics => new Dictionary<string, string>
{
{"Total Orders", "2"},
{"Average Win", "0.68%"},
{"Average Win", "2.19%"},
{"Average Loss", "0%"},
{"Compounding Annual Return", "24.075%"},
{"Drawdown", "1.900%"},
{"Compounding Annual Return", "100.016%"},
{"Drawdown", "3.600%"},
{"Expectancy", "0"},
{"Start Equity", "200000"},
{"End Equity", "201354"},
{"Net Profit", "0.677%"},
{"Sharpe Ratio", "5.76"},
{"End Equity", "204384"},
{"Net Profit", "2.192%"},
{"Sharpe Ratio", "9.169"},
{"Sortino Ratio", "0"},
{"Probabilistic Sharpe Ratio", "89.644%"},
{"Probabilistic Sharpe Ratio", "92.918%"},
{"Loss Rate", "0%"},
{"Win Rate", "100%"},
{"Profit-Loss Ratio", "0"},
{"Alpha", "0.946"},
{"Beta", "-0.354"},
{"Annual Standard Deviation", "0.123"},
{"Annual Variance", "0.015"},
{"Information Ratio", "0.211"},
{"Tracking Error", "0.176"},
{"Treynor Ratio", "-2.004"},
{"Alpha", "3.002"},
{"Beta", "-0.818"},
{"Annual Standard Deviation", "0.268"},
{"Annual Variance", "0.072"},
{"Information Ratio", "5.749"},
{"Tracking Error", "0.31"},
{"Treynor Ratio", "-2.999"},
{"Total Fees", "$0.00"},
{"Estimated Strategy Capacity", "$1700000.00"},
{"Lowest Capacity Asset", "SPX XL80P3HB9YI6|SPX 31"},
{"Portfolio Turnover", "0.35%"},
{"Estimated Strategy Capacity", "$420000.00"},
{"Lowest Capacity Asset", "SPX XL80P3GHIA9A|SPX 31"},
{"Portfolio Turnover", "2.37%"},
{"Drawdown Recovery", "10"},
{"OrderListHash", "d671fe71272a6c1b489d09071967a5de"}
{"OrderListHash", "0d2ccc2fdfa2b81bf71361c8248c4a59"}
};
}
}

View File

@@ -85,7 +85,7 @@ namespace QuantConnect.Algorithm.CSharp
{"Lowest Capacity Asset", "SPY R735QTJ8XC9X"},
{"Portfolio Turnover", "0.07%"},
{"Drawdown Recovery", "0"},
{"OrderListHash", "098dfba7feaa7389ceb7630aa7da2cfa"}
{"OrderListHash", "baab871855df123de17fb010951f55da"}
};
}
}

View File

@@ -186,7 +186,7 @@ namespace QuantConnect.Algorithm.CSharp
/// <summary>
/// Data Points count of all timeslices of algorithm
/// </summary>
public long DataPoints => 454078;
public long DataPoints => 455371;
/// <summary>
/// Data Points count of the algorithm history

View File

@@ -163,33 +163,33 @@ namespace QuantConnect.Algorithm.CSharp
public Dictionary<string, string> ExpectedStatistics => new Dictionary<string, string>
{
{"Total Orders", "3"},
{"Average Win", "0.68%"},
{"Average Win", "2.19%"},
{"Average Loss", "0%"},
{"Compounding Annual Return", "10.046%"},
{"Drawdown", "1.900%"},
{"Compounding Annual Return", "36.041%"},
{"Drawdown", "3.600%"},
{"Expectancy", "0"},
{"Start Equity", "200000"},
{"End Equity", "201353"},
{"Net Profit", "0.676%"},
{"Sharpe Ratio", "3.253"},
{"End Equity", "204383"},
{"Net Profit", "2.192%"},
{"Sharpe Ratio", "4.088"},
{"Sortino Ratio", "0"},
{"Probabilistic Sharpe Ratio", "86.292%"},
{"Probabilistic Sharpe Ratio", "89.872%"},
{"Loss Rate", "0%"},
{"Win Rate", "100%"},
{"Profit-Loss Ratio", "0"},
{"Alpha", "0"},
{"Beta", "0"},
{"Annual Standard Deviation", "0.081"},
{"Annual Variance", "0.007"},
{"Information Ratio", "3.284"},
{"Tracking Error", "0.081"},
{"Annual Standard Deviation", "0.177"},
{"Annual Variance", "0.031"},
{"Information Ratio", "4.102"},
{"Tracking Error", "0.177"},
{"Treynor Ratio", "0"},
{"Total Fees", "$1.00"},
{"Estimated Strategy Capacity", "$1700000.00"},
{"Lowest Capacity Asset", "SPX XL80P3HB9YI6|SPX 31"},
{"Portfolio Turnover", "0.16%"},
{"Estimated Strategy Capacity", "$420000.00"},
{"Lowest Capacity Asset", "SPX XL80P3GHIA9A|SPX 31"},
{"Portfolio Turnover", "1.09%"},
{"Drawdown Recovery", "10"},
{"OrderListHash", "be2eef3af814d254879e4c6902d9eb9c"}
{"OrderListHash", "e913c917ccb2641d70e8fffb47df4f02"}
};
}
}

View File

@@ -44,7 +44,7 @@ namespace QuantConnect.Algorithm.CSharp
var option = AddOption("GOOG");
_optionSymbol = option.Symbol;
option.SetFilter(-2, +2, 0, 180);
option.SetFilter(u => u.StandardsOnly().Strikes(-2, +2).Expiration(0, 180));
}
public override void OnData(Slice slice)

View File

@@ -113,7 +113,7 @@ namespace QuantConnect.Algorithm.CSharp
/// <summary>
/// Data Points count of all timeslices of algorithm
/// </summary>
public long DataPoints => 52987;
public long DataPoints => 50978;
/// <summary>
/// Data Points count of the algorithm history
@@ -133,31 +133,31 @@ namespace QuantConnect.Algorithm.CSharp
{"Total Orders", "2"},
{"Average Win", "0%"},
{"Average Loss", "0%"},
{"Compounding Annual Return", "120.870%"},
{"Drawdown", "3.700%"},
{"Compounding Annual Return", "-9.298%"},
{"Drawdown", "2.500%"},
{"Expectancy", "0"},
{"Start Equity", "100000"},
{"End Equity", "101091.4"},
{"Net Profit", "1.091%"},
{"Sharpe Ratio", "4.261"},
{"Sortino Ratio", "29.094"},
{"Probabilistic Sharpe Ratio", "58.720%"},
{"End Equity", "99866.4"},
{"Net Profit", "-0.134%"},
{"Sharpe Ratio", "1.959"},
{"Sortino Ratio", "4.863"},
{"Probabilistic Sharpe Ratio", "53.257%"},
{"Loss Rate", "0%"},
{"Win Rate", "0%"},
{"Profit-Loss Ratio", "0"},
{"Alpha", "1.134"},
{"Beta", "1.285"},
{"Annual Standard Deviation", "0.314"},
{"Annual Variance", "0.098"},
{"Information Ratio", "15.222"},
{"Tracking Error", "0.077"},
{"Treynor Ratio", "1.04"},
{"Alpha", "0.239"},
{"Beta", "0.695"},
{"Annual Standard Deviation", "0.178"},
{"Annual Variance", "0.032"},
{"Information Ratio", "2.059"},
{"Tracking Error", "0.093"},
{"Treynor Ratio", "0.501"},
{"Total Fees", "$4.30"},
{"Estimated Strategy Capacity", "$39000000.00"},
{"Lowest Capacity Asset", "ES VMKLFZIH2MTD"},
{"Portfolio Turnover", "33.59%"},
{"Drawdown Recovery", "3"},
{"OrderListHash", "8286cb0dd42649527c2c0032ee00e2bd"}
{"Estimated Strategy Capacity", "$25000000.00"},
{"Lowest Capacity Asset", "ES VU1EHIDJYLMP"},
{"Portfolio Turnover", "33.58%"},
{"Drawdown Recovery", "0"},
{"OrderListHash", "5a14a3f8b50e3117d87c69d6b11102fc"}
};
}
}

View File

@@ -50,7 +50,7 @@ namespace QuantConnect.Algorithm.CSharp
SetCash(500000);
var option = AddOption("GOOG");
option.SetFilter(universe => universe.Strikes(-3, 3).Expiration(0, 180));
option.SetFilter(universe => universe.StandardsOnly().Strikes(-3, 3).Expiration(0, 180));
_symbol = option.Symbol;
}

View File

@@ -143,7 +143,7 @@ namespace QuantConnect.Algorithm.CSharp
{"Lowest Capacity Asset", "SPY R735QTJ8XC9X"},
{"Portfolio Turnover", "0.02%"},
{"Drawdown Recovery", "0"},
{"OrderListHash", "dafe02af29d6a320da2e5dad28411559"}
{"OrderListHash", "9d53c0501981b8d3aa922bbc45b6e80f"}
};
}
}

View File

@@ -143,7 +143,7 @@ namespace QuantConnect.Algorithm.CSharp
{"Lowest Capacity Asset", "SPY R735QTJ8XC9X"},
{"Portfolio Turnover", "0.02%"},
{"Drawdown Recovery", "0"},
{"OrderListHash", "8940204f430a8040b372cc22d80f1399"}
{"OrderListHash", "e1d37155b945867337ae64a1807bf0ce"}
};
}
}

View File

@@ -90,7 +90,7 @@ namespace QuantConnect.Algorithm.CSharp
/// <summary>
/// Data Points count of all timeslices of algorithm
/// </summary>
public long DataPoints => 52987;
public long DataPoints => 50978;
/// <summary>
/// Data Points count of the algorithm history
@@ -110,31 +110,31 @@ namespace QuantConnect.Algorithm.CSharp
{"Total Orders", "2"},
{"Average Win", "0%"},
{"Average Loss", "0%"},
{"Compounding Annual Return", "113.036%"},
{"Drawdown", "3.700%"},
{"Compounding Annual Return", "-0.626%"},
{"Drawdown", "2.400%"},
{"Expectancy", "0"},
{"Start Equity", "100000"},
{"End Equity", "101041.4"},
{"Net Profit", "1.041%"},
{"Sharpe Ratio", "4.262"},
{"Sortino Ratio", "29.102"},
{"Probabilistic Sharpe Ratio", "58.720%"},
{"End Equity", "99991.4"},
{"Net Profit", "-0.009%"},
{"Sharpe Ratio", "1.959"},
{"Sortino Ratio", "4.862"},
{"Probabilistic Sharpe Ratio", "53.257%"},
{"Loss Rate", "0%"},
{"Win Rate", "0%"},
{"Profit-Loss Ratio", "0"},
{"Alpha", "1.135"},
{"Beta", "1.285"},
{"Annual Standard Deviation", "0.314"},
{"Annual Variance", "0.098"},
{"Information Ratio", "15.206"},
{"Tracking Error", "0.078"},
{"Treynor Ratio", "1.04"},
{"Alpha", "0.239"},
{"Beta", "0.694"},
{"Annual Standard Deviation", "0.177"},
{"Annual Variance", "0.031"},
{"Information Ratio", "2.05"},
{"Tracking Error", "0.093"},
{"Treynor Ratio", "0.501"},
{"Total Fees", "$4.30"},
{"Estimated Strategy Capacity", "$12000000.00"},
{"Lowest Capacity Asset", "ES VMKLFZIH2MTD"},
{"Portfolio Turnover", "33.61%"},
{"Estimated Strategy Capacity", "$15000000.00"},
{"Lowest Capacity Asset", "ES VU1EHIDJYLMP"},
{"Portfolio Turnover", "33.51%"},
{"Drawdown Recovery", "3"},
{"OrderListHash", "1a8899e6c1498f63634de38910878619"}
{"OrderListHash", "523d76e17b23ee0c94ded9f826cb8c22"}
};
}
}

View File

@@ -49,7 +49,7 @@ namespace QuantConnect.Algorithm.CSharp
var option = AddOption("GOOG");
_optionSymbol = option.Symbol;
option.SetFilter(-2, +2, 0, 180);
option.SetFilter(u => u.StandardsOnly().Strikes(-2, +2).Expiration(0, 180));
SetBenchmark("GOOG");
}

View File

@@ -44,7 +44,7 @@ namespace QuantConnect.Algorithm.CSharp
var option = AddOption(UnderlyingTicker);
_optionSymbol = option.Symbol;
option.SetFilter(u => u.Strikes(-2, +2).Expiration(0, 180 * 3));
option.SetFilter(u => u.StandardsOnly().Strikes(-2, +2).Expiration(0, 180 * 3));
SetBenchmark(equity.Symbol);
}

View File

@@ -47,7 +47,7 @@ namespace QuantConnect.Algorithm.CSharp
var option = AddOption(equity.Symbol);
_optionSymbol = option.Symbol;
option.SetFilter(-2, +2, 0, 180);
option.SetFilter(u => u.StandardsOnly().Strikes(-2, +2).Expiration(0, 180));
}
public override void OnData(Slice slice)

View File

@@ -45,7 +45,7 @@ namespace QuantConnect.Algorithm.CSharp
var option = AddOption(equity.Symbol);
OptionSymbol = option.Symbol;
option.SetFilter(u => u.Strikes(-2, +2).Expiration(0, 180));
option.SetFilter(u => u.StandardsOnly().Strikes(-2, +2).Expiration(0, 180));
}
protected virtual void OverrideMarginModels()
@@ -75,7 +75,7 @@ namespace QuantConnect.Algorithm.CSharp
.ThenBy(x => x.Strike)
.First();
if(!_placedTrades)
if (!_placedTrades)
{
_placedTrades = true;
PlaceTrades(atmContracts);
@@ -100,7 +100,7 @@ namespace QuantConnect.Algorithm.CSharp
{
throw new RegressionTestException($"Unexpected position group count {Portfolio.Positions.Groups.Count} for symbol {ticket.Symbol} and quantity {ticket.Quantity}");
}
if(Portfolio.TotalMarginUsed != expectedMarginUsed)
if (Portfolio.TotalMarginUsed != expectedMarginUsed)
{
throw new RegressionTestException($"Unexpected margin used {expectedMarginUsed}");
}

View File

@@ -133,10 +133,10 @@ namespace QuantConnect.Algorithm.CSharp
{"Treynor Ratio", "0"},
{"Total Fees", "$9.88"},
{"Estimated Strategy Capacity", "$0"},
{"Lowest Capacity Asset", "GC VMRHKN2NLWV1"},
{"Lowest Capacity Asset", "GC VOFJUCDY9XNH"},
{"Portfolio Turnover", "1.32%"},
{"Drawdown Recovery", "0"},
{"OrderListHash", "cc9ca77de1272050971b5438e757df61"}
{"OrderListHash", "4a7e699024771890b97c4ab74365e4b7"}
};
}
}

View File

@@ -38,10 +38,10 @@ namespace QuantConnect.Algorithm.CSharp
var option = GetOption();
var optionChainFromAlgorithmApi = OptionChain(option.Symbol).Contracts.Values.Select(x => x.Symbol).ToList();
var optionChainFromAlgorithmApi = OptionChain(option.Symbol).Contracts.Keys.ToList();
var exchangeTime = UtcTime.ConvertFromUtc(option.Exchange.TimeZone);
var optionChainFromProviderApi = OptionChainProvider.GetOptionContractList(option.Symbol, exchangeTime).ToList();
var optionChainFromProviderApi = OptionChainProvider.GetOptionContractList(option.Symbol, exchangeTime).Order().ToList();
if (optionChainFromAlgorithmApi.Count == 0)
{

View File

@@ -0,0 +1,143 @@
/*
* 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.Data;
using QuantConnect.Data.Market;
using QuantConnect.Interfaces;
using QuantConnect.Securities.Option;
using System.Collections.Generic;
namespace QuantConnect.Algorithm.CSharp
{
/// <summary>
/// Verifies that weekly option contracts are included when no standard contracts are available.
/// </summary>
public class OptionChainIncludeWeeklysByDefaultRegressionAlgorithm : QCAlgorithm, IRegressionAlgorithmDefinition
{
private Option _option;
private Symbol _optionSymbol;
private int _weeklyCount;
private int _totalCount;
/// <summary>
/// Initialise the data and resolution required, as well as the cash and start-end dates for your algorithm. All algorithms must initialized.
/// </summary>
public override void Initialize()
{
SetStartDate(2015, 12, 24);
SetEndDate(2015, 12, 24);
_option = AddOption("GOOG");
_optionSymbol = _option.Symbol;
_option.SetFilter((optionFilter) =>
{
return optionFilter.Strikes(-8, +8).Expiration(0, 0);
});
}
/// <summary>
/// OnData event is the primary entry point for your algorithm. Each new data point will be pumped in here.
/// </summary>
/// <param name="data">Slice object keyed by symbol containing the stock data</param>
public override void OnData(Slice slice)
{
OptionChain chain;
if (slice.OptionChains.TryGetValue(_optionSymbol, out chain))
{
_totalCount += chain.Contracts.Count;
foreach (var contract in chain.Contracts.Values)
{
if (!OptionSymbol.IsStandard(contract.Symbol))
{
_weeklyCount++;
}
}
}
}
public override void OnEndOfAlgorithm()
{
if (_weeklyCount == 0)
{
throw new RegressionTestException("No weekly contracts found");
}
if (_totalCount != _weeklyCount)
{
throw new RegressionTestException("When no standard option expirations are available, the option chain must fall back to weekly contracts only");
}
}
/// <summary>
/// This is used by the regression test system to indicate if the open source Lean repository has the required data to run this algorithm.
/// </summary>
public bool CanRunLocally { get; } = true;
/// <summary>
/// This is used by the regression test system to indicate which languages this algorithm is written in.
/// </summary>
public List<Language> Languages { get; } = new() { Language.CSharp, Language.Python };
/// <summary>
/// Data Points count of all timeslices of algorithm
/// </summary>
public long DataPoints => 22702;
/// <summary>
/// Data Points count of the algorithm history
/// </summary>
public int AlgorithmHistoryDataPoints => 0;
/// <summary>
/// Final status of the algorithm
/// </summary>
public AlgorithmStatus AlgorithmStatus => AlgorithmStatus.Completed;
/// <summary>
/// This is used by the regression test system to indicate what the expected statistics are from running the algorithm
/// </summary>
public Dictionary<string, string> ExpectedStatistics => new Dictionary<string, string>
{
{"Total Orders", "0"},
{"Average Win", "0%"},
{"Average Loss", "0%"},
{"Compounding Annual Return", "0%"},
{"Drawdown", "0%"},
{"Expectancy", "0"},
{"Start Equity", "100000"},
{"End Equity", "100000"},
{"Net Profit", "0%"},
{"Sharpe Ratio", "0"},
{"Sortino Ratio", "0"},
{"Probabilistic Sharpe Ratio", "0%"},
{"Loss Rate", "0%"},
{"Win Rate", "0%"},
{"Profit-Loss Ratio", "0"},
{"Alpha", "0"},
{"Beta", "0"},
{"Annual Standard Deviation", "0"},
{"Annual Variance", "0"},
{"Information Ratio", "0"},
{"Tracking Error", "0"},
{"Treynor Ratio", "0"},
{"Total Fees", "$0.00"},
{"Estimated Strategy Capacity", "$0"},
{"Lowest Capacity Asset", ""},
{"Portfolio Turnover", "0%"},
{"Drawdown Recovery", "0"},
{"OrderListHash", "d41d8cd98f00b204e9800998ecf8427e"}
};
}
}

View File

@@ -96,7 +96,7 @@ namespace QuantConnect.Algorithm.CSharp
protected override OptionFilterUniverse Filter(OptionFilterUniverse filter)
{
return filter.BackMonth().Contracts(contracts => contracts.Take(15));
return filter.StandardsOnly().BackMonth().Contracts(contracts => contracts.Take(15));
}
}

View File

@@ -36,7 +36,9 @@ namespace QuantConnect.Algorithm.CSharp
SetStartDate(2014, 06, 05);
SetEndDate(2014, 06, 09);
_aaplOption = AddOption("AAPL").Symbol;
var option = AddOption("AAPL");
option.SetFilter(u => u.StandardsOnly().Strikes(-1, 1).Expiration(0, 35));
_aaplOption = option.Symbol;
AddUniverseSelection(new DailyUniverseSelectionModel("MyCustomSelectionModel", time => new[] { "AAPL" }, this));
}

View File

@@ -28,7 +28,7 @@ namespace QuantConnect.Algorithm.CSharp
/// <summary>
/// Regression algorithm to test the OptionChainedUniverseSelectionModel class
/// </summary>
public class OptionChainedUniverseSelectionModelRegressionAlgorithm: QCAlgorithm, IRegressionAlgorithmDefinition
public class OptionChainedUniverseSelectionModelRegressionAlgorithm : QCAlgorithm, IRegressionAlgorithmDefinition
{
public override void Initialize()
{
@@ -39,7 +39,7 @@ namespace QuantConnect.Algorithm.CSharp
var universe = AddUniverse("my-minute-universe-name", time => new List<string> { "AAPL", "TWX" });
AddUniverseSelection(new OptionChainedUniverseSelectionModel(universe, u => u.Strikes(-2, +2)
AddUniverseSelection(new OptionChainedUniverseSelectionModel(universe, u => u.StandardsOnly().Strikes(-2, +2)
// Expiration method accepts TimeSpan objects or integer for days.
// The following statements yield the same filtering criteria
.Expiration(0, 180)));

View File

@@ -43,7 +43,7 @@ namespace QuantConnect.Algorithm.CSharp
_optionSymbol = option.Symbol;
// set our strike/expiry filter for this option chain
option.SetFilter(u => u.Strikes(-2, +2)
option.SetFilter(u => u.StandardsOnly().Strikes(-2, +2)
// Expiration method accepts TimeSpan objects or integer for days.
// The following statements yield the same filtering criteria
.Expiration(0, 180));
@@ -83,7 +83,7 @@ namespace QuantConnect.Algorithm.CSharp
spread = security.Price - security.Holdings.AveragePrice;
}
}
else if(security.BidPrice != 0)
else if (security.BidPrice != 0)
{
spread = security.Holdings.AveragePrice - security.Price;
}

View File

@@ -42,7 +42,7 @@ namespace QuantConnect.Algorithm.CSharp
_optionSymbol = option.Symbol;
// set our strike/expiry filter for this option chain
option.SetFilter(u => u.Strikes(-1, +1)
option.SetFilter(u => u.StandardsOnly().Strikes(-1, +1)
// Expiration method accepts TimeSpan objects or integer for days.
// The following statements yield the same filtering criteria
.Expiration(0, 60));

View File

@@ -42,7 +42,7 @@ namespace QuantConnect.Algorithm.CSharp
_aapl = AddEquity("AAPL", Resolution.Minute, extendedMarketHours: true, dataNormalizationMode: DataNormalizationMode.Raw).Symbol;
var option = AddOption(_aapl, Resolution.Minute);
option.SetFilter(-1, +1, 0, 365);
option.SetFilter(u => u.StandardsOnly().Strikes(-1, +1).Expiration(0, 365));
}
public override void OnData(Slice slice)

View File

@@ -30,6 +30,8 @@ namespace QuantConnect.Algorithm.CSharp
SetEndDate(2014, 6, 9);
var option = AddOption("AAPL", Resolution.Minute);
option.SetFilter(u => u.StandardsOnly().Strikes(-1, 1).Expiration(0, 35));
// BaroneAdesiWhaley model supports American style options
option.PriceModel = OptionPriceModels.BaroneAdesiWhaley();

View File

@@ -29,6 +29,8 @@ namespace QuantConnect.Algorithm.CSharp
SetEndDate(2014, 6, 9);
var option = AddOption("AAPL", Resolution.Minute);
option.SetFilter(u => u.StandardsOnly().Strikes(-1, 1).Expiration(0, 35));
// BlackSholes model does not support American style options
option.PriceModel = OptionPriceModels.BlackScholes();

View File

@@ -38,7 +38,7 @@ namespace QuantConnect.Algorithm.CSharp
UniverseSettings.Resolution = Resolution.Daily;
var option = AddOption("GOOG");
option.SetFilter(u => u.Strikes(-2, +2).Expiration(0, 180));
option.SetFilter(u => u.StandardsOnly().Strikes(-2, +2).Expiration(0, 180));
_optionSymbol = option.Symbol;
if (UniverseManager.TryGetValue(option.Symbol, out var universe)

View File

@@ -42,7 +42,7 @@ namespace QuantConnect.Algorithm.CSharp
var option = AddOption(equitySymbol);
_optionSymbol = option.Symbol;
option.SetFilter(u => u.Strikes(-2, +2)
option.SetFilter(u => u.StandardsOnly().Strikes(-2, +2)
.Expiration(0, 180));
Portfolio.MarginCallModel = new CustomMarginCallModel(Portfolio, DefaultOrderProperties);

View File

@@ -39,6 +39,7 @@ namespace QuantConnect.Algorithm.CSharp
SetEndDate(2014, 06, 09);
var option = AddOption("AAPL");
option.SetFilter(u => u.StandardsOnly().Strikes(-1, 1).Expiration(0, 35));
_optionSymbol = option.Symbol;
var optionContractSymbol = OptionChain(_optionSymbol)

View File

@@ -45,7 +45,7 @@ namespace QuantConnect.Algorithm.CSharp
var option = AddOption("GOOG");
_optionSymbol = option.Symbol;
option.SetFilter(-2, +2, 0, 180);
option.SetFilter(u => u.StandardsOnly().Strikes(-2, +2).Expiration(0, 180));
SetBenchmark("GOOG");
}
@@ -67,8 +67,7 @@ namespace QuantConnect.Algorithm.CSharp
var buyingPowerModel = positionGroup.BuyingPowerModel as OptionStrategyPositionGroupBuyingPowerModel;
if (buyingPowerModel == null)
{
throw new RegressionTestException($@"Expected position group buying power model type: {nameof(OptionStrategyPositionGroupBuyingPowerModel)
}. Actual: {positionGroup.BuyingPowerModel.GetType()}");
throw new RegressionTestException($@"Expected position group buying power model type: {nameof(OptionStrategyPositionGroupBuyingPowerModel)}. Actual: {positionGroup.BuyingPowerModel.GetType()}");
}
AssertStrategyPositionGroup(positionGroup);
@@ -91,9 +90,7 @@ namespace QuantConnect.Algorithm.CSharp
var ordersCount = Transactions.GetOrders((order) => order.Status == OrderStatus.Filled).Count();
if (ordersCount != ExpectedOrdersCount)
{
throw new RegressionTestException($@"Expected {ExpectedOrdersCount
} orders to have been submitted and filled, half for buying the strategy and the other half for the liquidation. Actual {
ordersCount}");
throw new RegressionTestException($@"Expected {ExpectedOrdersCount} orders to have been submitted and filled, half for buying the strategy and the other half for the liquidation. Actual {ordersCount}");
}
}

View File

@@ -49,7 +49,7 @@ namespace QuantConnect.Algorithm.CSharp
var option = AddOption(equity.Symbol);
option.SetFilter(u => u.Strikes(-2, +2).Expiration(0, 180));
option.SetFilter(u => u.StandardsOnly().Strikes(-2, +2).Expiration(0, 180));
}
public override void OnData(Slice slice)

View File

@@ -40,7 +40,7 @@ namespace QuantConnect.Algorithm.CSharp
// Subscribe to GOOG Options
var option = AddOption("GOOG");
option.SetFilter(x => x.CallsOnly().Strikes(0, 1).Expiration(0, 30));
option.SetFilter(x => x.StandardsOnly().CallsOnly().Strikes(0, 1).Expiration(0, 30));
}
public override void OnData(Slice slice)

View File

@@ -4,7 +4,7 @@
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<RootNamespace>QuantConnect.Algorithm.CSharp</RootNamespace>
<AssemblyName>QuantConnect.Algorithm.CSharp</AssemblyName>
<TargetFramework>net9.0</TargetFramework>
<TargetFramework>net10.0</TargetFramework>
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
<OutputPath>bin\$(Configuration)\</OutputPath>
<AnalysisMode>AllEnabledByDefault</AnalysisMode>
@@ -32,7 +32,7 @@
<DebugType>portable</DebugType>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="QuantConnect.pythonnet" Version="2.0.50" />
<PackageReference Include="QuantConnect.pythonnet" Version="2.0.52" />
<PackageReference Include="Accord" Version="3.6.0" />
<PackageReference Include="Accord.Fuzzy" Version="3.6.0" />
<PackageReference Include="Accord.MachineLearning" Version="3.6.0" />

View File

@@ -49,6 +49,7 @@ namespace QuantConnect.Algorithm.CSharp
var equitySymbol = AddEquity("GOOG", leverage: 4, fillForward: true).Symbol;
_option = AddOption(equitySymbol, fillForward: true);
_option.SetFilter(optionFilterUniverse => optionFilterUniverse
.StandardsOnly()
.Strikes(-2, 2)
.Expiration(0, 180));
}
@@ -136,17 +137,13 @@ namespace QuantConnect.Algorithm.CSharp
var expectedEntryQuantity = leg.Quantity * _comboQuantity;
if (entryOrderTicket.Quantity != expectedEntryQuantity || entryOrderTicket.QuantityFilled != expectedEntryQuantity)
{
throw new RegressionTestException($@"Entry order ticket quantity and filled quantity do not match expected quantity for leg {i
}. Expected: {expectedEntryQuantity}. Actual quantity: {entryOrderTicket.Quantity}. Actual filled quantity: {
entryOrderTicket.QuantityFilled}");
throw new RegressionTestException($@"Entry order ticket quantity and filled quantity do not match expected quantity for leg {i}. Expected: {expectedEntryQuantity}. Actual quantity: {entryOrderTicket.Quantity}. Actual filled quantity: {entryOrderTicket.QuantityFilled}");
}
var expectedExitQuantity = -expectedEntryQuantity;
if (exitOrderTicket.Quantity != expectedExitQuantity || exitOrderTicket.QuantityFilled != expectedExitQuantity)
{
throw new RegressionTestException($@"Exit order ticket quantity and filled quantity do not match expected quantity for leg {i
}. Expected: {expectedExitQuantity}. Actual quantity: {exitOrderTicket.Quantity}. Actual filled quantity: {
exitOrderTicket.QuantityFilled}");
throw new RegressionTestException($@"Exit order ticket quantity and filled quantity do not match expected quantity for leg {i}. Expected: {expectedExitQuantity}. Actual quantity: {exitOrderTicket.Quantity}. Actual filled quantity: {exitOrderTicket.QuantityFilled}");
}
}
}

View File

@@ -47,7 +47,7 @@ namespace QuantConnect.Algorithm.CSharp
SetCash(500000);
var option = AddOption("GOOG", Resolution.Minute);
option.SetFilter(universe => universe.Strikes(-1, 1).Expiration(0, 62));
option.SetFilter(universe => universe.StandardsOnly().Strikes(-1, 1).Expiration(0, 62));
_symbol = option.Symbol;
}

View File

@@ -36,7 +36,7 @@ namespace QuantConnect.Algorithm.CSharp
SetEndDate(2013, 10, 08);
Security = AddFuture(Futures.Metals.Gold, Resolution.Minute, extendedMarketHours: ExtendedMarketHours);
_futureContract = AddFutureContract(FuturesChain(Security.Symbol).First());
_futureContract = AddFutureContract(FuturesChain(Security.Symbol).OrderBy(x => x.Symbol.ID.Date).First());
// Manually add consolidators to simulate Session behavior
_continuousContractConsolidator = new MarketHourAwareConsolidator(false, Resolution.Daily, typeof(QuoteBar), TickType.Quote, false);

View File

@@ -44,7 +44,7 @@ namespace QuantConnect.Algorithm.CSharp
var option = AddOption(equitySymbol);
_optionSymbol = option.Symbol;
option.SetFilter(u => u.Strikes(-2, +2).Expiration(0, 180));
option.SetFilter(u => u.StandardsOnly().Strikes(-2, +2).Expiration(0, 180));
}
public override void OnData(Slice slice)
@@ -124,8 +124,7 @@ namespace QuantConnect.Algorithm.CSharp
if (positionQuantityForDeltaWithPositionGroupBuyingPowerModel != expectedQuantity)
{
throw new RegressionTestException($@"Expected position quantity for delta buying power to be {expectedQuantity} but was {
positionQuantityForDeltaWithPositionGroupBuyingPowerModel}");
throw new RegressionTestException($@"Expected position quantity for delta buying power to be {expectedQuantity} but was {positionQuantityForDeltaWithPositionGroupBuyingPowerModel}");
}
var position = positionGroup.Positions.Single();
@@ -144,8 +143,7 @@ namespace QuantConnect.Algorithm.CSharp
if (positionQuantityForDeltaWithSecurityPositionGroupBuyingPowerModel != expectedSingleSecurityModelsQuantity ||
positionQuantityForDeltaWithSecurityBuyingPowerModel != expectedSingleSecurityModelsQuantity)
{
throw new RegressionTestException($@"Expected order quantity for delta buying power calls from default buying power models to return {
expectedSingleSecurityModelsQuantity}. Results were:" +
throw new RegressionTestException($@"Expected order quantity for delta buying power calls from default buying power models to return {expectedSingleSecurityModelsQuantity}. Results were:" +
$" \nSecurityPositionGroupBuyingPowerModel: {positionQuantityForDeltaWithSecurityPositionGroupBuyingPowerModel}" +
$" \nBuyingPowerModel: {positionQuantityForDeltaWithSecurityBuyingPowerModel}\n");
}

View File

@@ -54,7 +54,8 @@ namespace QuantConnect.Algorithm.CSharp
{
if (Time.Hour == 9 && Time.Minute == 58)
{
AddOption(UnderlyingTicker);
var option = AddOption(UnderlyingTicker);
option.SetFilter(u => u.StandardsOnly().Strikes(-1, 1).Expiration(0, 35));
}
AssertValue(slice);

View File

@@ -0,0 +1,135 @@
/*
* 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.Data;
using QuantConnect.Interfaces;
using System.Collections.Generic;
using QuantConnect.Data.Fundamental;
using QuantConnect.Data.UniverseSelection;
namespace QuantConnect.Algorithm.CSharp
{
/// <summary>
/// Regression test algorithm for scheduled universe selection GH 3890
/// </summary>
public class YearlyUniverseSelectionScheduleRegressionAlgorithm : QCAlgorithm, IRegressionAlgorithmDefinition
{
private int _yearlyDateSelection;
private readonly Symbol _symbol = QuantConnect.Symbol.Create("SPY", SecurityType.Equity, Market.USA);
/// <summary>
/// Initialise the data and resolution required, as well as the cash and start-end dates for your algorithm. All algorithms must initialized.
/// </summary>
public override void Initialize()
{
SetStartDate(2014, 03, 25);
SetEndDate(2014, 05, 10);
UniverseSettings.Resolution = Resolution.Daily;
AddUniverse(DateRules.YearStart(), SelectionFunction);
}
public IEnumerable<Symbol> SelectionFunction(IEnumerable<Fundamental> coarse)
{
_yearlyDateSelection++;
if (Time != StartDate)
{
throw new RegressionTestException($"SelectionFunction_SpecificDate unexpected selection: {Time}");
}
return new[] { _symbol };
}
/// <summary>
/// OnData event is the primary entry point for your algorithm. Each new data point will be pumped in here.
/// </summary>
/// <param name="slice">Slice object keyed by symbol containing the stock data</param>
public override void OnData(Slice slice)
{
if (!Portfolio.Invested)
{
SetHoldings(_symbol, 1);
Debug($"Purchased Stock {_symbol}");
}
}
public override void OnEndOfAlgorithm()
{
if (_yearlyDateSelection != 1)
{
throw new RegressionTestException($"Initial yearly selection didn't happen!");
}
}
/// <summary>
/// Data Points count of all timeslices of algorithm
/// </summary>
public long DataPoints => 271;
/// <summary>
/// Data Points count of the algorithm history
/// </summary>
public int AlgorithmHistoryDataPoints => 0;
/// <summary>
/// Final status of the algorithm
/// </summary>
public AlgorithmStatus AlgorithmStatus => AlgorithmStatus.Completed;
/// <summary>
/// This is used by the regression test system to indicate if the open source Lean repository has the required data to run this algorithm.
/// </summary>
public bool CanRunLocally { get; } = true;
/// <summary>
/// This is used by the regression test system to indicate which languages this algorithm is written in.
/// </summary>
public List<Language> Languages { get; } = new() { Language.CSharp };
/// <summary>
/// This is used by the regression test system to indicate what the expected statistics are from running the algorithm
/// </summary>
public Dictionary<string, string> ExpectedStatistics => new Dictionary<string, string>
{
{"Total Orders", "1"},
{"Average Win", "0%"},
{"Average Loss", "0%"},
{"Compounding Annual Return", "4.334%"},
{"Drawdown", "3.900%"},
{"Expectancy", "0"},
{"Start Equity", "100000"},
{"End Equity", "100532.22"},
{"Net Profit", "0.532%"},
{"Sharpe Ratio", "0.28"},
{"Sortino Ratio", "0.283"},
{"Probabilistic Sharpe Ratio", "39.422%"},
{"Loss Rate", "0%"},
{"Win Rate", "0%"},
{"Profit-Loss Ratio", "0"},
{"Alpha", "-0.022"},
{"Beta", "1.018"},
{"Annual Standard Deviation", "0.099"},
{"Annual Variance", "0.01"},
{"Information Ratio", "-2.462"},
{"Tracking Error", "0.009"},
{"Treynor Ratio", "0.027"},
{"Total Fees", "$3.07"},
{"Estimated Strategy Capacity", "$920000000.00"},
{"Lowest Capacity Asset", "SPY R735QTJ8XC9X"},
{"Portfolio Turnover", "2.20%"},
{"Drawdown Recovery", "5"},
{"OrderListHash", "87438e51988f37757a2d7f97389483ea"}
};
}
}

View File

@@ -36,17 +36,6 @@ namespace QuantConnect.Algorithm.Framework.Alphas
private readonly HashSet<Security> _securities;
private readonly Dictionary<Symbol, DateTime> _insightsTimeBySymbol;
/// <summary>
/// Initializes a new instance of the <see cref="ConstantAlphaModel"/> class
/// </summary>
/// <param name="type">The type of insight</param>
/// <param name="direction">The direction of the insight</param>
/// <param name="period">The period over which the insight with come to fruition</param>
public ConstantAlphaModel(InsightType type, InsightDirection direction, TimeSpan period)
: this(type, direction, period, null, null)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="ConstantAlphaModel"/> class
/// </summary>
@@ -56,7 +45,7 @@ namespace QuantConnect.Algorithm.Framework.Alphas
/// <param name="magnitude">The predicted change in magnitude as a +- percentage</param>
/// <param name="confidence">The confidence in the insight</param>
/// <param name="weight">The portfolio weight of the insights</param>
public ConstantAlphaModel(InsightType type, InsightDirection direction, TimeSpan period, double? magnitude, double? confidence, double? weight = null)
public ConstantAlphaModel(InsightType type, InsightDirection direction, TimeSpan period, double? magnitude = null, double? confidence = null, double? weight = null)
{
_type = type;
_direction = direction;
@@ -127,7 +116,7 @@ namespace QuantConnect.Algorithm.Framework.Alphas
/// <param name="symbol">The symbol to emit an insight for</param>
protected virtual bool ShouldEmitInsight(DateTime utcTime, Symbol symbol)
{
if(symbol.IsCanonical())
if (symbol.IsCanonical())
{
// canonical futures & options are none tradable
return false;

View File

@@ -4,7 +4,7 @@
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<RootNamespace>QuantConnect.Algorithm.Framework</RootNamespace>
<AssemblyName>QuantConnect.Algorithm.Framework</AssemblyName>
<TargetFramework>net9.0</TargetFramework>
<TargetFramework>net10.0</TargetFramework>
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
<OutputPath>bin\$(Configuration)\</OutputPath>
<AnalysisMode>AllEnabledByDefault</AnalysisMode>
@@ -29,7 +29,7 @@
<PackageLicenseFile>LICENSE</PackageLicenseFile>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="QuantConnect.pythonnet" Version="2.0.50" />
<PackageReference Include="QuantConnect.pythonnet" Version="2.0.52" />
<PackageReference Include="Accord" Version="3.6.0" />
<PackageReference Include="Accord.Math" Version="3.6.0" />
<PackageReference Include="Accord.Statistics" Version="3.6.0" />

View File

@@ -17,19 +17,19 @@ class FundamentalUniverseSelectionModel:
'''Provides a base class for defining equity coarse/fine fundamental selection models'''
def __init__(self,
filterFineData = None,
universeSettings = None):
filter_fine_data = None,
universe_settings = None):
'''Initializes a new instance of the FundamentalUniverseSelectionModel class
Args:
filterFineData: [Obsolete] Fine and Coarse selection are merged
universeSettings: The settings used when adding symbols to the algorithm, specify null to use algorithm.UniverseSettings'''
self.filter_fine_data = filterFineData
filter_fine_data: [Obsolete] Fine and Coarse selection are merged
universeSettings: The settings used when adding symbols to the algorithm, specify null to use algorithm.universe_settings'''
self.filter_fine_data = filter_fine_data
if self.filter_fine_data == None:
self.fundamental_data = True
else:
self.fundamental_data = False
self.market = Market.USA
self.universe_settings = universeSettings
self.universe_settings = universe_settings
def create_universes(self, algorithm: QCAlgorithm) -> list[Universe]:

View File

@@ -33,7 +33,7 @@ class BasicTemplateOptionEquityStrategyAlgorithm(QCAlgorithm):
self._option_symbol = option.symbol
# set our strike/expiry filter for this option chain
option.set_filter(lambda u: (u.strikes(-2, +2)
option.set_filter(lambda u: (u.standards_only().strikes(-2, +2)
# Expiration method accepts TimeSpan objects or integer for days.
# The following statements yield the same filtering criteria
.expiration(0, 180)))

View File

@@ -39,8 +39,7 @@ class BasicTemplateOptionStrategyAlgorithm(QCAlgorithm):
# set our strike/expiry filter for this option chain
# SetFilter method accepts timedelta objects or integer for days.
# The following statements yield the same filtering criteria
option.set_filter(-2, +2, 0, 180)
# option.set_filter(-2,2, timedelta(0), timedelta(180))
option.set_filter(lambda u: (u.standards_only().strikes(-2, +2).expiration(0, 180)))
# use the underlying equity as the benchmark
self.set_benchmark("GOOG")

View File

@@ -34,7 +34,7 @@ class BasicTemplateOptionsAlgorithm(QCAlgorithm):
self.option_symbol = option.symbol
# set our strike/expiry filter for this option chain
option.set_filter(lambda u: (u.strikes(-2, +2)
option.set_filter(lambda u: (u.standards_only().strikes(-2, +2)
# Expiration method accepts TimeSpan objects or integer for days.
# The following statements yield the same filtering criteria
.expiration(0, 180)))

View File

@@ -34,7 +34,7 @@ class BasicTemplateOptionsHourlyAlgorithm(QCAlgorithm):
self.option_symbol = option.symbol
# set our strike/expiry filter for this option chain
option.set_filter(lambda u: (u.strikes(-2, +2)
option.set_filter(lambda u: (u.standards_only().strikes(-2, +2)
# Expiration method accepts TimeSpan objects or integer for days.
# The following statements yield the same filtering criteria
.expiration(0, 180)))

View File

@@ -28,7 +28,7 @@ class ComboOrderTicketDemoAlgorithm(QCAlgorithm):
option = self.add_option(equity.symbol, fill_forward=True)
self._option_symbol = option.symbol
option.set_filter(lambda u: u.strikes(-2, +2).expiration(0, 180))
option.set_filter(lambda u: u.standards_only().strikes(-2, +2).expiration(0, 180))
self._open_market_orders = []
self._open_leg_limit_orders = []

View File

@@ -25,7 +25,7 @@ class ConsolidateRegressionAlgorithm(QCAlgorithm):
self.set_end_date(2020, 1, 20)
SP500 = Symbol.create(Futures.Indices.SP_500_E_MINI, SecurityType.FUTURE, Market.CME)
symbol = list(self.futures_chain(SP500))[0]
symbol = list(sorted(self.futures_chain(SP500).contracts.keys(), key=lambda symbol: symbol.id.date))[0]
self._future = self.add_future_contract(symbol)
tradable_dates_count = len(list(Time.each_tradeable_day_in_time_zone(self._future.exchange.hours,

View File

@@ -26,7 +26,7 @@ class FutureOptionMultipleContractsInDifferentContractMonthsWithSameUnderlyingFu
self._create_option(datetime(2020, 2, 25), OptionRight.CALL, 1600.0): False,
self._create_option(datetime(2020, 2, 25), OptionRight.PUT, 1545.0): False
}
# Required for FOPs to use extended hours, until GH #6491 is addressed
self.universe_settings.extended_market_hours = True
@@ -34,9 +34,9 @@ class FutureOptionMultipleContractsInDifferentContractMonthsWithSameUnderlyingFu
self.set_end_date(2020, 1, 6)
gold_futures = self.add_future("GC", Resolution.MINUTE, Market.COMEX, extended_market_hours=True)
gold_futures.SetFilter(0, 365)
gold_futures.set_filter(0, 365)
self.add_future_option(gold_futures.Symbol)
self.add_future_option(gold_futures.symbol)
def on_data(self, data: Slice):
for symbol in data.quote_bars.keys():

View File

@@ -32,7 +32,7 @@ class HistoryAlgorithm(QCAlgorithm):
self.add_equity("SPY", Resolution.DAILY)
IBM = self.add_data(CustomDataEquity, "IBM", Resolution.DAILY)
# specifying the exchange will allow the history methods that accept a number of bars to return to work properly
IBM.Exchange = EquityExchange()
IBM.exchange = EquityExchange()
# we can get history in initialize to set up indicators and such
self.daily_sma = SimpleMovingAverage(14)
@@ -96,7 +96,7 @@ class HistoryAlgorithm(QCAlgorithm):
self.assert_history_count("History(CustomDataEquity, self.securities.keys(), 14)", all_custom_data, 14 * 2)
# NOTE: Using different resolutions require that they are properly implemented in your data type. If your
# custom data source has different resolutions, it would need to be implemented in the GetSource and
# custom data source has different resolutions, it would need to be implemented in the GetSource and
# Reader methods properly.
#custom_data_history = self.history(CustomDataEquity, "IBM", timedelta(7), Resolution.MINUTE)
#custom_data_history = self.history(CustomDataEquity, "IBM", 14, Resolution.MINUTE)

View File

@@ -33,7 +33,7 @@ class NullBuyingPowerOptionBullCallSpreadAlgorithm(QCAlgorithm):
option = self.add_option(equity.symbol)
self.option_symbol = option.symbol
option.set_filter(-2, 2, 0, 180)
option.set_filter(lambda u: u.standards_only().strikes(-2, +2).expiration(0, 180))
def on_data(self, slice):
if self.portfolio.invested or not self.is_market_open(self.option_symbol):

View File

@@ -32,7 +32,7 @@ class NullMarginMultipleOrdersRegressionAlgorithm(QCAlgorithm):
option = self.add_option(equity.symbol, fill_forward=True)
self._option_symbol = option.symbol
option.set_filter(lambda u: u.strikes(-2, +2).expiration(0, 180))
option.set_filter(lambda u: u.standards_only().strikes(-2, +2).expiration(0, 180))
def on_data(self, data: Slice):
if not self.portfolio.invested:

View File

@@ -28,10 +28,10 @@ class OptionChainApisConsistencyRegressionAlgorithm(QCAlgorithm):
option = self.get_option()
option_chain_from_algorithm_api = [x.symbol for x in self.option_chain(option.symbol).contracts.values()]
option_chain_from_algorithm_api = self.option_chain(option.symbol).contracts.keys()
exchange_time = Extensions.convert_from_utc(self.utc_time, option.exchange.time_zone)
option_chain_from_provider_api = list(self.option_chain_provider.get_option_contract_list(option.symbol, exchange_time))
option_chain_from_provider_api = list(sorted(self.option_chain_provider.get_option_contract_list(option.symbol, exchange_time)))
if len(option_chain_from_algorithm_api) == 0:
raise AssertionError("No options in chain from algorithm API")

View File

@@ -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.
from AlgorithmImports import *
### <summary>
### Verifies that weekly option contracts are included when no standard contracts are available.
### </summary>
class OptionChainIncludeWeeklysByDefaultRegressionAlgorithm(QCAlgorithm):
def initialize(self):
self.set_start_date(2015, 12, 24)
self.set_end_date(2015, 12, 24)
self.option = self.add_option("GOOG")
self.option_symbol = self.option.Symbol
self.option.set_filter(lambda u: u.strikes(-8, 8).expiration(0, 0))
self.weekly_count = 0
self.total_count = 0
def on_data(self, data):
chain = data.option_chains.get(self.option_symbol)
if chain:
self.total_count += len(chain.contracts)
for contract in chain.contracts.values():
if not OptionSymbol.is_standard(contract.symbol):
self.weekly_count += 1
def on_end_of_algorithm(self):
if self.weekly_count == 0:
raise RegressionTestException("No weekly contracts found")
if self.total_count != self.weekly_count:
raise RegressionTestException("When no standard option expirations are available, the option chain must fall back to weekly contracts only")

View File

@@ -28,7 +28,7 @@ class OptionChainedUniverseSelectionModelRegressionAlgorithm(QCAlgorithm):
self.add_universe_selection(
OptionChainedUniverseSelectionModel(
universe,
lambda u: (u.strikes(-2, +2)
lambda u: (u.standards_only().strikes(-2, +2)
# Expiration method accepts TimeSpan objects or integer for days.
# The following statements yield the same filtering criteria
.expiration(0, 180))

View File

@@ -24,6 +24,8 @@ class OptionPriceModelForSupportedAmericanOptionRegressionAlgorithm(OptionPriceM
self.set_end_date(2014, 6, 9)
option = self.add_option("AAPL", Resolution.MINUTE)
option.set_filter(lambda u: u.standards_only().strikes(-1, 1).expiration(0, 35))
# BaroneAdesiWhaley model supports American style options
option.price_model = OptionPriceModels.barone_adesi_whaley()

View File

@@ -24,6 +24,8 @@ class OptionPriceModelForUnsupportedAmericanOptionRegressionAlgorithm(OptionPric
self.set_end_date(2014, 6, 9)
option = self.add_option("AAPL", Resolution.MINUTE)
option.set_filter(lambda u: u.standards_only().strikes(-1, 1).expiration(0, 35))
# BlackSholes model does not support American style options
option.price_model = OptionPriceModels.black_scholes()

View File

@@ -27,7 +27,7 @@ class OptionStrategyFactoryMethodsBaseAlgorithm(QCAlgorithm):
option = self.add_option("GOOG")
self._option_symbol = option.symbol
option.set_filter(-2, +2, 0, 180)
option.set_filter(lambda u: u.standards_only().strikes(-2, +2).expiration(0, 180))
self.set_benchmark("GOOG")

View File

@@ -4,7 +4,7 @@
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<RootNamespace>QuantConnect.Algorithm.Python</RootNamespace>
<AssemblyName>QuantConnect.Algorithm.Python</AssemblyName>
<TargetFramework>net9.0</TargetFramework>
<TargetFramework>net10.0</TargetFramework>
<AnalysisMode>AllEnabledByDefault</AnalysisMode>
<OutputPath>bin\$(Configuration)\</OutputPath>
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
@@ -37,7 +37,7 @@
<Compile Include="..\Common\Properties\SharedAssemblyInfo.cs" Link="Properties\SharedAssemblyInfo.cs" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="QuantConnect.pythonnet" Version="2.0.50" />
<PackageReference Include="QuantConnect.pythonnet" Version="2.0.52" />
</ItemGroup>
<ItemGroup>
<Content Include="OptionUniverseFilterGreeksShortcutsRegressionAlgorithm.py" />

View File

@@ -20,18 +20,18 @@ class ScheduledQueuingAlgorithm(QCAlgorithm):
self.set_start_date(2020, 9, 1)
self.set_end_date(2020, 9, 2)
self.set_cash(100000)
self.__number_of_symbols = 2000
self.__number_of_symbols_fine = 1000
self.set_universe_selection(FineFundamentalUniverseSelectionModel(self.coarse_selection_function, self.fine_selection_function, None))
self.set_portfolio_construction(EqualWeightingPortfolioConstructionModel())
self.set_execution(ImmediateExecutionModel())
self._queue = Queue()
self._dequeue_size = 100
self.add_equity("SPY", Resolution.MINUTE)
self.schedule.on(self.date_rules.every_day("SPY"), self.time_rules.at(0, 0), self.fill_queue)
self.schedule.on(self.date_rules.every_day("SPY"), self.time_rules.every(timedelta(minutes=60)), self.take_from_queue)
@@ -40,22 +40,22 @@ class ScheduledQueuingAlgorithm(QCAlgorithm):
has_fundamentals = [security for security in coarse if security.has_fundamental_data]
sorted_by_dollar_volume = sorted(has_fundamentals, key=lambda x: x.dollar_volume, reverse=True)
return [ x.symbol for x in sorted_by_dollar_volume[:self.__number_of_symbols] ]
def fine_selection_function(self, fine: list[FineFundamental]) -> list[Symbol]:
sorted_by_pe_ratio = sorted(fine, key=lambda x: x.valuation_ratios.pe_ratio, reverse=True)
return [ x.symbol for x in sorted_by_pe_ratio[:self.__number_of_symbols_fine] ]
def fill_queue(self) -> None:
securities = [security for security in self.active_securities.values if security.fundamentals]
securities = [security for security in self.active_securities.values() if security.fundamentals]
# Fill queue with symbols sorted by PE ratio (decreasing order)
self._queue.queue.clear()
sorted_by_pe_ratio = sorted(securities, key=lambda x: x.fundamentals.valuation_ratios.pe_ratio, reverse=True)
for security in sorted_by_pe_ratio:
self._queue.put(security.symbol)
def take_from_queue(self) -> None:
symbols = [self._queue.get() for _ in range(min(self._dequeue_size, self._queue.qsize()))]
self.history(symbols, 10, Resolution.DAILY)
self.log(f"Symbols at {self.time}: {[str(symbol) for symbol in symbols]}")

View File

@@ -116,11 +116,10 @@ namespace QuantConnect.Algorithm.Framework.Alphas
/// <param name="pyAlphaModel">The alpha model to add</param>
public void AddAlpha(PyObject pyAlphaModel)
{
IAlphaModel alphaModel;
if (!pyAlphaModel.TryConvert(out alphaModel))
{
alphaModel = new AlphaModelPythonWrapper(pyAlphaModel);
}
var alphaModel = PythonUtil.CreateInstanceOrWrapper<IAlphaModel>(
pyAlphaModel,
py => new AlphaModelPythonWrapper(py)
);
_alphaModels.Add(alphaModel);
}
}

View File

@@ -29,7 +29,7 @@ namespace QuantConnect.Algorithm
private readonly IAlgorithm _algorithm;
/// <summary>
/// Universe which selects companies whose revenues and earnings have both been growing significantly faster than
/// <see cref="Universe"/> which selects companies whose revenues and earnings have both been growing significantly faster than
/// the general economy.
/// </summary>
public Universe AggressiveGrowth(UniverseSettings universeSettings = null)
@@ -40,7 +40,7 @@ namespace QuantConnect.Algorithm
}
/// <summary>
/// Universe which selects companies that are growing respectably faster than the general economy, and often pay a
/// <see cref="Universe"/> which selects companies that are growing respectably faster than the general economy, and often pay a
/// steady dividend. They tend to be mature and solidly profitable businesses.
/// </summary>
public Universe ClassicGrowth(UniverseSettings universeSettings = null)
@@ -51,7 +51,7 @@ namespace QuantConnect.Algorithm
}
/// <summary>
/// Universe which selects companies in the cyclicals and durables sectors, except those in the three types below.
/// <see cref="Universe"/> which selects companies in the cyclicals and durables sectors, except those in the three types below.
/// The profits of cyclicals tend to rise and fall with the general economy.
/// </summary>
public Universe Cyclicals(UniverseSettings universeSettings = null)
@@ -62,7 +62,7 @@ namespace QuantConnect.Algorithm
}
/// <summary>
/// Universe which selects companies that have had consistently declining cash flows and earnings over the past
/// <see cref="Universe"/> which selects companies that have had consistently declining cash flows and earnings over the past
/// three years, and/or very high debt.
/// </summary>
public Universe Distressed(UniverseSettings universeSettings = null)
@@ -73,7 +73,7 @@ namespace QuantConnect.Algorithm
}
/// <summary>
/// Universe which selects companies that deal in assets such as oil, metals, and real estate, which tend to do
/// <see cref="Universe"/> which selects companies that deal in assets such as oil, metals, and real estate, which tend to do
/// well in inflationary environments.
/// </summary>
public Universe HardAsset(UniverseSettings universeSettings = null)
@@ -84,7 +84,7 @@ namespace QuantConnect.Algorithm
}
/// <summary>
/// Universe which selects companies that have dividend yields at least twice the average for large-cap stocks.
/// <see cref="Universe"/> which selects companies that have dividend yields at least twice the average for large-cap stocks.
/// They tend to be mature, slow-growing companies.
/// </summary>
public Universe HighYield(UniverseSettings universeSettings = null)
@@ -95,7 +95,7 @@ namespace QuantConnect.Algorithm
}
/// <summary>
/// Universe which selects companies that have shown slow revenue and earnings growth (typically less than the rate
/// <see cref="Universe"/> which selects companies that have shown slow revenue and earnings growth (typically less than the rate
/// of GDP growth) over at least three years.
/// </summary>
public Universe SlowGrowth(UniverseSettings universeSettings = null)
@@ -106,7 +106,7 @@ namespace QuantConnect.Algorithm
}
/// <summary>
/// Universe which selects companies that have shown strong revenue growth but slower or spotty earnings growth.
/// <see cref="Universe"/> which selects companies that have shown strong revenue growth but slower or spotty earnings growth.
/// Very small or young companies also tend to fall into this class.
/// </summary>
public Universe SpeculativeGrowth(UniverseSettings universeSettings = null)

View File

@@ -40,7 +40,7 @@ namespace QuantConnect.Algorithm
}
/// <summary>
/// Creates a new coarse universe that contains the top count of stocks
/// Creates a new coarse <see cref="Universe"/> that contains the top count of stocks
/// by daily dollar volume
/// </summary>
/// <param name="count">The number of stock to select</param>

View File

@@ -19,6 +19,7 @@ using QuantConnect.Algorithm.Framework.Execution;
using QuantConnect.Algorithm.Framework.Portfolio;
using QuantConnect.Algorithm.Framework.Risk;
using QuantConnect.Algorithm.Framework.Selection;
using QuantConnect.Util;
namespace QuantConnect.Algorithm
{
@@ -31,15 +32,10 @@ namespace QuantConnect.Algorithm
[DocumentationAttribute(AlgorithmFramework)]
public void SetAlpha(PyObject alpha)
{
IAlphaModel model;
if (alpha.TryConvert(out model))
{
SetAlpha(model);
}
else
{
Alpha = new AlphaModelPythonWrapper(alpha);
}
Alpha = PythonUtil.CreateInstanceOrWrapper<IAlphaModel>(
alpha,
py => new AlphaModelPythonWrapper(py)
);
}
/// <summary>
@@ -49,15 +45,11 @@ namespace QuantConnect.Algorithm
[DocumentationAttribute(AlgorithmFramework)]
public void AddAlpha(PyObject alpha)
{
IAlphaModel model;
if (alpha.TryConvert(out model))
{
AddAlpha(model);
}
else
{
AddAlpha(new AlphaModelPythonWrapper(alpha));
}
var model = PythonUtil.CreateInstanceOrWrapper<IAlphaModel>(
alpha,
py => new AlphaModelPythonWrapper(py)
);
AddAlpha(model);
}
/// <summary>
@@ -68,15 +60,10 @@ namespace QuantConnect.Algorithm
[DocumentationAttribute(TradingAndOrders)]
public void SetExecution(PyObject execution)
{
IExecutionModel model;
if (execution.TryConvert(out model))
{
SetExecution(model);
}
else
{
Execution = new ExecutionModelPythonWrapper(execution);
}
Execution = PythonUtil.CreateInstanceOrWrapper<IExecutionModel>(
execution,
py => new ExecutionModelPythonWrapper(py)
);
}
/// <summary>
@@ -87,15 +74,10 @@ namespace QuantConnect.Algorithm
[DocumentationAttribute(TradingAndOrders)]
public void SetPortfolioConstruction(PyObject portfolioConstruction)
{
IPortfolioConstructionModel model;
if (portfolioConstruction.TryConvert(out model))
{
SetPortfolioConstruction(model);
}
else
{
PortfolioConstruction = new PortfolioConstructionModelPythonWrapper(portfolioConstruction);
}
PortfolioConstruction = PythonUtil.CreateInstanceOrWrapper<IPortfolioConstructionModel>(
portfolioConstruction,
py => new PortfolioConstructionModelPythonWrapper(py)
);
}
/// <summary>
@@ -106,12 +88,10 @@ namespace QuantConnect.Algorithm
[DocumentationAttribute(Universes)]
public void SetUniverseSelection(PyObject universeSelection)
{
IUniverseSelectionModel model;
if (!universeSelection.TryConvert(out model))
{
model = new UniverseSelectionModelPythonWrapper(universeSelection);
}
SetUniverseSelection(model);
UniverseSelection = PythonUtil.CreateInstanceOrWrapper<IUniverseSelectionModel>(
universeSelection,
py => new UniverseSelectionModelPythonWrapper(py)
);
}
/// <summary>
@@ -122,11 +102,10 @@ namespace QuantConnect.Algorithm
[DocumentationAttribute(Universes)]
public void AddUniverseSelection(PyObject universeSelection)
{
IUniverseSelectionModel model;
if (!universeSelection.TryConvert(out model))
{
model = new UniverseSelectionModelPythonWrapper(universeSelection);
}
var model = PythonUtil.CreateInstanceOrWrapper<IUniverseSelectionModel>(
universeSelection,
py => new UniverseSelectionModelPythonWrapper(py)
);
AddUniverseSelection(model);
}
@@ -138,15 +117,10 @@ namespace QuantConnect.Algorithm
[DocumentationAttribute(TradingAndOrders)]
public void SetRiskManagement(PyObject riskManagement)
{
IRiskManagementModel model;
if (riskManagement.TryConvert(out model))
{
SetRiskManagement(model);
}
else
{
RiskManagement = new RiskManagementModelPythonWrapper(riskManagement);
}
RiskManagement = PythonUtil.CreateInstanceOrWrapper<IRiskManagementModel>(
riskManagement,
py => new RiskManagementModelPythonWrapper(py)
);
}
/// <summary>
@@ -157,11 +131,10 @@ namespace QuantConnect.Algorithm
[DocumentationAttribute(TradingAndOrders)]
public void AddRiskManagement(PyObject riskManagement)
{
IRiskManagementModel model;
if (!riskManagement.TryConvert(out model))
{
model = new RiskManagementModelPythonWrapper(riskManagement);
}
var model = PythonUtil.CreateInstanceOrWrapper<IRiskManagementModel>(
riskManagement,
py => new RiskManagementModelPythonWrapper(py)
);
AddRiskManagement(model);
}
}

View File

@@ -79,8 +79,8 @@ namespace QuantConnect.Algorithm
public IRiskManagementModel RiskManagement { get; set; }
/// <summary>
/// Called by setup handlers after Initialize and allows the algorithm a chance to organize
/// the data gather in the Initialize method
/// Called by setup handlers after <see cref="Initialize"/> and allows the algorithm a chance to organize
/// the data gather in the <see cref="Initialize"/> method
/// </summary>
[DocumentationAttribute(AlgorithmFramework)]
public void FrameworkPostInitialize()
@@ -100,7 +100,7 @@ namespace QuantConnect.Algorithm
/// <summary>
/// Used to send data updates to algorithm framework models
/// </summary>
/// <param name="slice">The current data slice</param>
/// <param name="slice">The current data <see cref="Slice"/></param>
[DocumentationAttribute(AlgorithmFramework)]
[DocumentationAttribute(HandlingData)]
public void OnFrameworkData(Slice slice)
@@ -166,12 +166,12 @@ namespace QuantConnect.Algorithm
}
/// <summary>
/// They different framework models will process the new provided insight.
/// They different framework models will process the new provided <see cref="Insight"/>.
/// The <see cref="IPortfolioConstructionModel"/> will create targets,
/// the <see cref="IRiskManagementModel"/> will adjust the targets
/// and the <see cref="IExecutionModel"/> will execute the <see cref="IPortfolioTarget"/>
/// </summary>
/// <param name="insights">The insight to process</param>
/// <param name="insights">The <see cref="Insight"/> to process</param>
[DocumentationAttribute(AlgorithmFramework)]
private void ProcessInsights(Insight[] insights)
{
@@ -179,7 +179,7 @@ namespace QuantConnect.Algorithm
var targetsEnumerable = PortfolioConstruction.CreateTargets(this, insights);
// for performance only call 'ToArray' if not empty enumerable (which is static)
var targets = targetsEnumerable == Enumerable.Empty<IPortfolioTarget>()
? new IPortfolioTarget[] {} : targetsEnumerable.ToArray();
? new IPortfolioTarget[] { } : targetsEnumerable.ToArray();
// set security targets w/ those generated via portfolio construction module
foreach (var target in targets)

View File

@@ -31,10 +31,10 @@ namespace QuantConnect.Algorithm
{
public partial class QCAlgorithm
{
private readonly int SeedLookbackPeriod = Config.GetInt("seed-lookback-period", 5);
private readonly int SeedRetryMinuteLookbackPeriod = Config.GetInt("seed-retry-minute-lookback-period", 24 * 60);
private readonly int SeedRetryHourLookbackPeriod = Config.GetInt("seed-retry-hour-lookback-period", 24);
private readonly int SeedRetryDailyLookbackPeriod = Config.GetInt("seed-retry-daily-lookback-period", 10);
private static readonly int SeedLookbackPeriod = Config.GetInt("seed-lookback-period", 5);
private static readonly int SeedRetryMinuteLookbackPeriod = Config.GetInt("seed-retry-minute-lookback-period", 24 * 60);
private static readonly int SeedRetryHourLookbackPeriod = Config.GetInt("seed-retry-hour-lookback-period", 24);
private static readonly int SeedRetryDailyLookbackPeriod = Config.GetInt("seed-retry-daily-lookback-period", 10);
private bool _dataDictionaryTickWarningSent;
@@ -742,7 +742,7 @@ namespace QuantConnect.Algorithm
/// <returns>Securities historical data</returns>
[DocumentationAttribute(AddingData)]
[DocumentationAttribute(HistoricalData)]
public Dictionary<Symbol, IEnumerable<BaseData>> GetLastKnownPrices(IEnumerable<Security> securities)
public DataDictionary<IEnumerable<BaseData>> GetLastKnownPrices(IEnumerable<Security> securities)
{
return GetLastKnownPrices(securities.Select(s => s.Symbol));
}
@@ -754,11 +754,11 @@ namespace QuantConnect.Algorithm
/// <returns>Securities historical data</returns>
[DocumentationAttribute(AddingData)]
[DocumentationAttribute(HistoricalData)]
public Dictionary<Symbol, IEnumerable<BaseData>> GetLastKnownPrices(IEnumerable<Symbol> symbols)
public DataDictionary<IEnumerable<BaseData>> GetLastKnownPrices(IEnumerable<Symbol> symbols)
{
if (HistoryProvider == null)
{
return new Dictionary<Symbol, IEnumerable<BaseData>>();
return new DataDictionary<IEnumerable<BaseData>>();
}
var data = new Dictionary<(Symbol, Type, TickType), BaseData>();
@@ -766,10 +766,12 @@ namespace QuantConnect.Algorithm
return data
.GroupBy(kvp => kvp.Key.Item1)
.ToDictionary(g => g.Key,
.ToDataDictionary(
g => g.Key,
g => g.OrderBy(kvp => kvp.Value.Time)
.ThenBy(kvp => GetTickTypeOrder(kvp.Key.Item1.SecurityType, kvp.Key.Item3))
.Select(kvp => kvp.Value));
.Select(kvp => kvp.Value)
);
}
/// <summary>
@@ -1281,6 +1283,15 @@ namespace QuantConnect.Algorithm
}
else
{
// let's try to respect already added user settings, even if resolution/type don't match, like Tick vs Bars
var userConfigIfAny = subscriptions.FirstOrDefault(x => LeanData.IsCommonLeanDataType(x.Type) && !x.IsInternalFeed);
// Inherit values from existing subscriptions or use defaults
var extendedMarketHours = userConfigIfAny?.ExtendedMarketHours ?? UniverseSettings.ExtendedMarketHours;
var dataNormalizationMode = userConfigIfAny?.DataNormalizationMode ?? UniverseSettings.GetUniverseNormalizationModeOrDefault(symbol.SecurityType);
var dataMappingMode = userConfigIfAny?.DataMappingMode ?? UniverseSettings.GetUniverseMappingModeOrDefault(symbol.SecurityType, symbol.ID.Market);
var contractDepthOffset = userConfigIfAny?.ContractDepthOffset ?? (uint)Math.Abs(UniverseSettings.ContractDepthOffset);
// If type was specified and not a lean data type and also not abstract, we create a new subscription
if (type != null && !LeanData.IsCommonLeanDataType(type) && !type.IsAbstract)
{
@@ -1304,17 +1315,16 @@ namespace QuantConnect.Algorithm
entry.DataTimeZone,
entry.ExchangeHours.TimeZone,
UniverseSettings.FillForward,
UniverseSettings.ExtendedMarketHours,
extendedMarketHours,
true,
isCustom,
LeanData.GetCommonTickTypeForCommonDataTypes(dataType, symbol.SecurityType),
true,
UniverseSettings.GetUniverseNormalizationModeOrDefault(symbol.SecurityType))};
dataNormalizationMode,
dataMappingMode,
contractDepthOffset)};
}
// let's try to respect already added user settings, even if resolution/type don't match, like Tick vs Bars
var userConfigIfAny = subscriptions.FirstOrDefault(x => LeanData.IsCommonLeanDataType(x.Type) && !x.IsInternalFeed);
var res = GetResolution(symbol, resolution, type);
return SubscriptionManager
.LookupSubscriptionConfigDataTypes(symbol.SecurityType, res,
@@ -1335,14 +1345,14 @@ namespace QuantConnect.Algorithm
entry.DataTimeZone,
entry.ExchangeHours.TimeZone,
UniverseSettings.FillForward,
userConfigIfAny?.ExtendedMarketHours ?? UniverseSettings.ExtendedMarketHours,
extendedMarketHours,
true,
false,
x.Item2,
true,
userConfigIfAny?.DataNormalizationMode ?? UniverseSettings.GetUniverseNormalizationModeOrDefault(symbol.SecurityType),
userConfigIfAny?.DataMappingMode ?? UniverseSettings.GetUniverseMappingModeOrDefault(symbol.SecurityType, symbol.ID.Market),
userConfigIfAny?.ContractDepthOffset ?? (uint)Math.Abs(UniverseSettings.ContractDepthOffset));
dataNormalizationMode,
dataMappingMode,
contractDepthOffset);
})
// lets make sure to respect the order of the data types, if used on a history request will affect outcome when using pushthrough for example
.OrderByDescending(config => GetTickTypeOrder(config.SecurityType, config.TickType));

View File

@@ -53,7 +53,8 @@ namespace QuantConnect.Algorithm
"IsReady",
"Window",
"Item",
"WarmUpPeriod"
"WarmUpPeriod",
"Period"
};
/// <summary>
@@ -489,6 +490,26 @@ namespace QuantConnect.Algorithm
return correlation;
}
/// <summary>
/// Creates a Covariance indicator for the given target symbol in relation with the reference used.
/// The indicator will be automatically updated on the given resolution.
/// </summary>
/// <param name="target">The target symbol whose Covariance value we want</param>
/// <param name="reference">The reference symbol to compare with the target symbol</param>
/// <param name="period">The period of the Covariance indicator</param>
/// <param name="resolution">The resolution</param>
/// <param name="selector">Selects a value from the BaseData to send into the indicator, if null defaults to casting the input value to a TradeBar</param>
/// <returns>The Covariance indicator for the given parameters</returns>
[DocumentationAttribute(Indicators)]
public Covariance COV(Symbol target, Symbol reference, int period, Resolution? resolution = null, Func<IBaseData, IBaseDataBar> selector = null)
{
var name = CreateIndicatorName(QuantConnect.Symbol.None, $"COV({period})", resolution);
var covariance = new Covariance(name, target, reference, period);
InitializeIndicator(covariance, resolution, selector, target, reference);
return covariance;
}
/// <summary>
/// Creates a new CommodityChannelIndex indicator. The indicator will be automatically
/// updated on the given resolution.
@@ -1691,6 +1712,50 @@ namespace QuantConnect.Algorithm
return normalizedAverageTrueRange;
}
/// <summary>
/// Creates a new New Highs - New Lows indicator
/// </summary>
/// <param name="symbols">The symbols whose NHNL we want</param>
/// <param name="period">The period over which to compute the NHNL</param>
/// <param name="resolution">The resolution</param>
/// <param name="selector">Selects a value from the BaseData to send into the indicator, if null defaults to casting the input value to a IBaseDataBar</param>
/// <returns>The NewHighsNewLows indicator for the requested symbols over the specified period</returns>
[DocumentationAttribute(Indicators)]
public NewHighsNewLows NHNL(IEnumerable<Symbol> symbols, int period, Resolution? resolution = null, Func<IBaseData, IBaseDataBar> selector = null)
{
var name = CreateIndicatorName(QuantConnect.Symbol.None, $"NH/NL({period})", resolution ?? GetSubscription(symbols.First()).Resolution);
var nhnlDifference = new NewHighsNewLows(name, period);
foreach (var symbol in symbols)
{
nhnlDifference.Add(symbol);
}
InitializeIndicator(nhnlDifference, resolution, selector, symbols.ToArray());
return nhnlDifference;
}
/// <summary>
/// Creates a new New Highs - New Lows Volume indicator
/// </summary>
/// <param name="symbols">The symbols whose NHNLV we want</param>
/// <param name="period">The period over which to compute the NHNLV</param>
/// <param name="resolution">The resolution</param>
/// <param name="selector">Selects a value from the BaseData to send into the indicator, if null defaults to casting the input value to a TradeBar</param>
/// <returns>The NewHighsNewLowsVolume indicator for the requested symbols over the specified period</returns>
[DocumentationAttribute(Indicators)]
public NewHighsNewLowsVolume NHNLV(IEnumerable<Symbol> symbols, int period, Resolution? resolution = null, Func<IBaseData, TradeBar> selector = null)
{
var name = CreateIndicatorName(QuantConnect.Symbol.None, $"NH/NL Volume({period})", resolution ?? GetSubscription(symbols.First()).Resolution);
var nhnlVolume = new NewHighsNewLowsVolume(name, period);
foreach (var symbol in symbols)
{
nhnlVolume.Add(symbol);
}
InitializeIndicator(nhnlVolume, resolution, selector, symbols.ToArray());
return nhnlVolume;
}
/// <summary>
/// Creates a new On Balance Volume indicator. This will compute the cumulative total volume
/// based on whether the close price being higher or lower than the previous period.
@@ -2215,7 +2280,7 @@ namespace QuantConnect.Algorithm
return targetDownsideDeviation;
}
/// <summary>
/// Creates a new TomDemark Sequential candlestick indicator for the symbol. The indicator will be automatically
/// updated on the symbol's subscription resolution.

View File

@@ -497,6 +497,12 @@ namespace QuantConnect.Algorithm
[DocumentationAttribute(StatisticsTag)]
public void SetSummaryStatistic(string name, string value)
{
if (int.TryParse(name, NumberStyles.Integer, CultureInfo.InvariantCulture, out var intName) &&
intName >= 0 && intName <= 100)
{
throw new ArgumentException($"'{name}' is a reserved statistic name.");
}
_statisticsService.SetSummaryStatistic(name, value);
}
@@ -508,7 +514,7 @@ namespace QuantConnect.Algorithm
[DocumentationAttribute(StatisticsTag)]
public void SetSummaryStatistic(string name, int value)
{
_statisticsService.SetSummaryStatistic(name, value.ToStringInvariant());
SetSummaryStatistic(name, value.ToStringInvariant());
}
/// <summary>
@@ -519,7 +525,7 @@ namespace QuantConnect.Algorithm
[DocumentationAttribute(StatisticsTag)]
public void SetSummaryStatistic(string name, double value)
{
_statisticsService.SetSummaryStatistic(name, value.ToStringInvariant());
SetSummaryStatistic(name, value.ToStringInvariant());
}
/// <summary>
@@ -530,7 +536,7 @@ namespace QuantConnect.Algorithm
[DocumentationAttribute(StatisticsTag)]
public void SetSummaryStatistic(string name, decimal value)
{
_statisticsService.SetSummaryStatistic(name, value.ToStringInvariant());
SetSummaryStatistic(name, value.ToStringInvariant());
}
/// <summary>

View File

@@ -1372,12 +1372,10 @@ namespace QuantConnect.Algorithm
[DocumentationAttribute(Modeling)]
public void SetBrokerageModel(PyObject model)
{
IBrokerageModel brokerageModel;
if (!model.TryConvert(out brokerageModel))
{
brokerageModel = new BrokerageModelPythonWrapper(model);
}
var brokerageModel = PythonUtil.CreateInstanceOrWrapper<IBrokerageModel>(
model,
py => new BrokerageModelPythonWrapper(py)
);
SetBrokerageModel(brokerageModel);
}
@@ -1392,11 +1390,10 @@ namespace QuantConnect.Algorithm
[DocumentationAttribute(Logging)]
public void SetBrokerageMessageHandler(PyObject handler)
{
if (!handler.TryConvert(out IBrokerageMessageHandler brokerageMessageHandler))
{
brokerageMessageHandler = new BrokerageMessageHandlerPythonWrapper(handler);
}
var brokerageMessageHandler = PythonUtil.CreateInstanceOrWrapper<IBrokerageMessageHandler>(
handler,
py => new BrokerageMessageHandlerPythonWrapper(py)
);
SetBrokerageMessageHandler(brokerageMessageHandler);
}
@@ -1407,7 +1404,11 @@ namespace QuantConnect.Algorithm
[DocumentationAttribute(Modeling)]
public void SetRiskFreeInterestRateModel(PyObject model)
{
SetRiskFreeInterestRateModel(RiskFreeInterestRateModelPythonWrapper.FromPyObject(model));
var riskFreeInterestRateModel = PythonUtil.CreateInstanceOrWrapper<IRiskFreeInterestRateModel>(
model,
py => new RiskFreeInterestRateModelPythonWrapper(py)
);
SetRiskFreeInterestRateModel(riskFreeInterestRateModel);
}
/// <summary>

View File

@@ -58,6 +58,7 @@ using QuantConnect.Commands;
using Newtonsoft.Json;
using QuantConnect.Securities.Index;
using QuantConnect.Api;
using Common.Util;
namespace QuantConnect.Algorithm
{
@@ -256,7 +257,7 @@ namespace QuantConnect.Algorithm
public event AlgorithmEvent<GeneratedInsightsCollection> InsightsGenerated;
/// <summary>
/// Security collection is an array of the security objects such as Equities and FOREX. Securities data
/// Security collection is an array of the security objects such as <see cref="Equity"/> and <see cref="Forex"/>. Securities data
/// manages the properties of tradeable assets such as price, open and close time and holdings information.
/// </summary>
[DocumentationAttribute(SecuritiesAndPortfolio)]
@@ -271,7 +272,7 @@ namespace QuantConnect.Algorithm
/// a security that is currently selected by the universe or has holdings or open orders.
/// </summary>
[DocumentationAttribute(SecuritiesAndPortfolio)]
public IReadOnlyDictionary<Symbol, Security> ActiveSecurities => UniverseManager.ActiveSecurities;
public ReadOnlyExtendedDictionary<Symbol, Security> ActiveSecurities => UniverseManager.ActiveSecurities;
/// <summary>
/// Portfolio object provieds easy access to the underlying security-holding properties; summed together in a way to make them useful.
@@ -839,11 +840,6 @@ namespace QuantConnect.Algorithm
SetFinishedWarmingUp();
}
if (Settings.DailyPreciseEndTime)
{
Debug("Accurate daily end-times now enabled by default. See more at https://qnt.co/3YHaWHL. To disable it and use legacy daily bars set self.settings.daily_precise_end_time = False.");
}
// perform end of time step checks, such as enforcing underlying securities are in raw data mode
OnEndOfTimeStep();
}
@@ -914,9 +910,9 @@ namespace QuantConnect.Algorithm
/// Gets a read-only dictionary with all current parameters
/// </summary>
[DocumentationAttribute(ParameterAndOptimization)]
public IReadOnlyDictionary<string, string> GetParameters()
public ReadOnlyExtendedDictionary<string, string> GetParameters()
{
return _parameters.ToReadOnlyDictionary();
return _parameters.ToReadOnlyExtendedDictionary();
}
/// <summary>
@@ -1247,6 +1243,7 @@ namespace QuantConnect.Algorithm
/// <summary>
/// Brokerage message event handler. This method is called for all types of brokerage messages.
/// </summary>
/// <param name="messageEvent">The brokerage message event instance containing the message details.</param>
[DocumentationAttribute(LiveTrading)]
[DocumentationAttribute(Modeling)]
[DocumentationAttribute(TradingAndOrders)]
@@ -1440,7 +1437,7 @@ namespace QuantConnect.Algorithm
/// Sets the benchmark used for computing statistics of the algorithm to the specified symbol
/// </summary>
/// <param name="symbol">symbol to use as the benchmark</param>
/// <param name="securityType">Is the symbol an equity, forex, base, etc. Default SecurityType.Equity</param>
/// <param name="securityType">Is the symbol an equity, forex, base, etc. Default <see cref="SecurityType.Equity"/></param>
/// <remarks>
/// Must use symbol that is available to the trade engine in your data store(not strictly enforced)
/// </remarks>
@@ -1462,12 +1459,12 @@ namespace QuantConnect.Algorithm
}
/// <summary>
/// Sets the benchmark used for computing statistics of the algorithm to the specified ticker, defaulting to SecurityType.Equity
/// Sets the benchmark used for computing statistics of the algorithm to the specified ticker, defaulting to <see cref="SecurityType.Equity"/>
/// if the ticker doesn't exist in the algorithm
/// </summary>
/// <param name="ticker">Ticker to use as the benchmark</param>
/// <remarks>
/// Overload to accept ticker without passing SecurityType. If ticker is in portfolio it will use that SecurityType, otherwise will default to SecurityType.Equity
/// Overload to accept ticker without passing <see cref="SecurityType"/>. If ticker is in portfolio it will use that <see cref="SecurityType"/>, otherwise will default to <see cref="SecurityType.Equity"/>
/// </remarks>
[DocumentationAttribute(TradingAndOrders)]
[DocumentationAttribute(SecuritiesAndPortfolio)]
@@ -1531,9 +1528,9 @@ namespace QuantConnect.Algorithm
}
/// <summary>
/// Benchmark
/// The <see cref="IBenchmark"/> for the algorithm
/// </summary>
/// <remarks>Use Benchmark to override default symbol based benchmark, and create your own benchmark. For example a custom moving average benchmark </remarks>
/// <remarks>Use <see cref="IBenchmark"/> for the algorithm to override default symbol based benchmark, and create your own benchmark. For example a custom moving average benchmark </remarks>
///
[DocumentationAttribute(TradingAndOrders)]
[DocumentationAttribute(SecuritiesAndPortfolio)]
@@ -1622,7 +1619,7 @@ namespace QuantConnect.Algorithm
/// and replaced with the actual cash of your brokerage account.
/// </summary>
/// <param name="startingCash">Starting cash for the strategy backtest</param>
/// <remarks>Alias of SetCash(decimal)</remarks>
/// <remarks>Alias of <see cref="SetCash(decimal)"/></remarks>
[DocumentationAttribute(SecuritiesAndPortfolio)]
public void SetCash(double startingCash)
{
@@ -1634,7 +1631,7 @@ namespace QuantConnect.Algorithm
/// and replaced with the actual cash of your brokerage account.
/// </summary>
/// <param name="startingCash">Starting cash for the strategy backtest</param>
/// <remarks>Alias of SetCash(decimal)</remarks>
/// <remarks>Alias of <see cref="SetCash(decimal)"/></remarks>
[DocumentationAttribute(SecuritiesAndPortfolio)]
public void SetCash(int startingCash)
{
@@ -1746,7 +1743,7 @@ namespace QuantConnect.Algorithm
/// <summary>
/// Set the start date for the backtest
/// </summary>
/// <param name="start">Datetime Start date for backtest</param>
/// <param name="start">The start date for the backtest</param>
/// <remarks>Must be less than end date and within data available</remarks>
/// <seealso cref="SetStartDate(int, int, int)"/>
[DocumentationAttribute(HandlingData)]
@@ -2148,7 +2145,7 @@ namespace QuantConnect.Algorithm
/// </summary>
/// <param name="underlying">Underlying asset Symbol to use as the option's underlying</param>
/// <param name="resolution">The <see cref="Resolution"/> of market data, Tick, Second, Minute, Hour, or Daily. Default is <see cref="Resolution.Minute"/></param>
/// <param name="market">The option's market, <seealso cref="Market"/>. Default value is null, but will be resolved using BrokerageModel.DefaultMarkets in <see cref="AddSecurity{T}"/></param>
/// <param name="market">The option's market, <seealso cref="Market"/>. Default value is null, but will be resolved using <see cref="IBrokerageModel.DefaultMarkets"/> in <see cref="AddSecurity{T}"/></param>
/// <param name="fillForward">If true, data will be provided to the algorithm every Second, Minute, Hour, or Day, while the asset is open and depending on the Resolution this option was configured to use.</param>
/// <param name="leverage">The requested leverage for the </param>
/// <returns>The new option security instance</returns>
@@ -2167,7 +2164,7 @@ namespace QuantConnect.Algorithm
/// <param name="underlying">Underlying asset Symbol to use as the option's underlying</param>
/// <param name="targetOption">The target option ticker. This is useful when the option ticker does not match the underlying, e.g. SPX index and the SPXW weekly option. If null is provided will use underlying</param>
/// <param name="resolution">The <see cref="Resolution"/> of market data, Tick, Second, Minute, Hour, or Daily. Default is <see cref="Resolution.Minute"/></param>
/// <param name="market">The option's market, <seealso cref="Market"/>. Default value is null, but will be resolved using BrokerageModel.DefaultMarkets in <see cref="AddSecurity{T}"/></param>
/// <param name="market">The option's market, <seealso cref="Market"/>. Default value is null, but will be resolved using <see cref="IBrokerageModel.DefaultMarkets"/> in <see cref="AddSecurity{T}"/></param>
/// <param name="fillForward">If true, data will be provided to the algorithm every Second, Minute, Hour, or Day, while the asset is open and depending on the Resolution this option was configured to use.</param>
/// <param name="leverage">The requested leverage for the </param>
/// <returns>The new option security instance</returns>
@@ -2206,9 +2203,9 @@ namespace QuantConnect.Algorithm
/// </summary>
/// <param name="ticker">The future ticker</param>
/// <param name="resolution">The <see cref="Resolution"/> of market data, Tick, Second, Minute, Hour, or Daily. Default is <see cref="Resolution.Minute"/></param>
/// <param name="market">The futures market, <seealso cref="Market"/>. Default is value null and looked up using BrokerageModel.DefaultMarkets in <see cref="AddSecurity{T}"/></param>
/// <param name="market">The futures market, <seealso cref="Market"/>. Default is value null and looked up using <see cref="IBrokerageModel.DefaultMarkets"> in <see cref="AddSecurity{T}"/></param>
/// <param name="fillForward">If true, returns the last available data even if none in that timeslice. Default is <value>true</value></param>
/// <param name="leverage">The requested leverage for this equity. Default is set by <see cref="SecurityInitializer"/></param>
/// <param name="leverage">The requested leverage for this future. Default is set by <see cref="SecurityInitializer"/></param>
/// <param name="extendedMarketHours">Use extended market hours data</param>
/// <param name="dataMappingMode">The contract mapping mode to use for the continuous future contract</param>
/// <param name="dataNormalizationMode">The price scaling mode to use for the continuous future contract</param>
@@ -2241,7 +2238,7 @@ namespace QuantConnect.Algorithm
/// <param name="symbol">The futures contract symbol</param>
/// <param name="resolution">The <see cref="Resolution"/> of market data, Tick, Second, Minute, Hour, or Daily. Default is <see cref="Resolution.Minute"/></param>
/// <param name="fillForward">If true, returns the last available data even if none in that timeslice. Default is <value>true</value></param>
/// <param name="leverage">The requested leverage for this equity. Default is set by <see cref="SecurityInitializer"/></param>
/// <param name="leverage">The requested leverage for this future. Default is set by <see cref="SecurityInitializer"/></param>
/// <param name="extendedMarketHours">Use extended market hours data</param>
/// <returns>The new <see cref="Future"/> security</returns>
[DocumentationAttribute(AddingData)]
@@ -2301,12 +2298,13 @@ namespace QuantConnect.Algorithm
/// <summary>
/// Creates and adds index options to the algorithm.
/// </summary>
/// <param name="underlying">The underlying ticker of the Index Option</param>
/// <param name="underlying">The underlying ticker of the <see cref="IndexOption"/></param>
/// <param name="resolution">Resolution of the index option contracts, i.e. the granularity of the data</param>
/// <param name="market">The foreign exchange trading market, <seealso cref="Market"/>. Default value is null and looked up using BrokerageModel.DefaultMarkets in <see cref="AddSecurity{T}"/></param>
/// <param name="market">The foreign exchange trading market, <seealso cref="Market"/>. Default value is null and looked up using <see cref="IBrokerageModel.DefaultMarkets"/> in <see cref="AddSecurity{T}"/></param>
/// <param name="fillForward">If true, this will fill in missing data points with the previous data point</param>
/// <returns>Canonical Option security</returns>
[DocumentationAttribute(AddingData)]
public IndexOption AddIndexOption(string underlying, Resolution? resolution = null, string market = null, bool fillForward = true)
{
return AddIndexOption(underlying, null, resolution, market, fillForward);
@@ -2350,7 +2348,7 @@ namespace QuantConnect.Algorithm
/// <param name="underlying">The underlying ticker of the Index Option</param>
/// <param name="targetOption">The target option ticker. This is useful when the option ticker does not match the underlying, e.g. SPX index and the SPXW weekly option. If null is provided will use underlying</param>
/// <param name="resolution">Resolution of the index option contracts, i.e. the granularity of the data</param>
/// <param name="market">The foreign exchange trading market, <seealso cref="Market"/>. Default value is null and looked up using BrokerageModel.DefaultMarkets in <see cref="AddSecurity{T}"/></param>
/// <param name="market">The foreign exchange trading market, <seealso cref="Market"/>. Default value is null and looked up using <see cref="IBrokerageModel.DefaultMarkets"> in <see cref="AddSecurity{T}"/></param>
/// <param name="fillForward">If true, this will fill in missing data points with the previous data point</param>
/// <returns>Canonical Option security</returns>
[DocumentationAttribute(AddingData)]
@@ -2368,7 +2366,7 @@ namespace QuantConnect.Algorithm
/// <param name="resolution">Resolution of the index option contract, i.e. the granularity of the data</param>
/// <param name="fillForward">If true, this will fill in missing data points with the previous data point</param>
/// <returns>Index Option Contract</returns>
/// <exception cref="ArgumentException">The provided Symbol is not an Index Option</exception>
/// <exception cref="ArgumentException">The provided Symbol is not an <see cref="IndexOption"/></exception>
[DocumentationAttribute(AddingData)]
public IndexOption AddIndexOptionContract(Symbol symbol, Resolution? resolution = null, bool fillForward = true)
{
@@ -2386,7 +2384,7 @@ namespace QuantConnect.Algorithm
/// <param name="symbol">The option contract symbol</param>
/// <param name="resolution">The <see cref="Resolution"/> of market data, Tick, Second, Minute, Hour, or Daily. Default is <see cref="Resolution.Minute"/></param>
/// <param name="fillForward">If true, returns the last available data even if none in that timeslice. Default is <value>true</value></param>
/// <param name="leverage">The requested leverage for this equity. Default is set by <see cref="SecurityInitializer"/></param>
/// <param name="leverage">The requested leverage for this option. Default is set by <see cref="SecurityInitializer"/></param>
/// <param name="extendedMarketHours">Use extended market hours data</param>
/// <returns>The new <see cref="Option"/> security</returns>
[DocumentationAttribute(AddingData)]
@@ -2481,9 +2479,9 @@ namespace QuantConnect.Algorithm
/// </summary>
/// <param name="ticker">The currency pair</param>
/// <param name="resolution">The <see cref="Resolution"/> of market data, Tick, Second, Minute, Hour, or Daily. Default is <see cref="Resolution.Minute"/></param>
/// <param name="market">The foreign exchange trading market, <seealso cref="Market"/>. Default value is null and looked up using BrokerageModel.DefaultMarkets in <see cref="AddSecurity{T}"/></param>
/// <param name="market">The foreign exchange trading market, <seealso cref="Market"/>. Default value is null and looked up using <see cref="IBrokerageModel.DefaultMarkets" /> in <see cref="AddSecurity{T}"/></param>
/// <param name="fillForward">If true, returns the last available data even if none in that timeslice. Default is <value>true</value></param>
/// <param name="leverage">The requested leverage for this equity. Default is set by <see cref="SecurityInitializer"/></param>
/// <param name="leverage">The requested leverage for this forex security. Default is set by <see cref="SecurityInitializer"/></param>
/// <returns>The new <see cref="Forex"/> security</returns>
[DocumentationAttribute(AddingData)]
public Forex AddForex(string ticker, Resolution? resolution = null, string market = null, bool fillForward = true, decimal leverage = Security.NullLeverage)
@@ -2494,11 +2492,11 @@ namespace QuantConnect.Algorithm
/// <summary>
/// Creates and adds a new <see cref="Cfd"/> security to the algorithm
/// </summary>
/// <param name="ticker">The currency pair</param>
/// <param name="ticker">The CFD ticker symbol</param>
/// <param name="resolution">The <see cref="Resolution"/> of market data, Tick, Second, Minute, Hour, or Daily. Default is <see cref="Resolution.Minute"/></param>
/// <param name="market">The cfd trading market, <seealso cref="Market"/>. Default value is null and looked up using BrokerageModel.DefaultMarkets in <see cref="AddSecurity{T}"/></param>
/// <param name="market">The cfd trading market, <seealso cref="Market"/>. Default value is null and looked up using <see cref="IBrokerageModel.DefaultMarkets"/> in <see cref="AddSecurity{T}"/></param>
/// <param name="fillForward">If true, returns the last available data even if none in that timeslice. Default is <value>true</value></param>
/// <param name="leverage">The requested leverage for this equity. Default is set by <see cref="SecurityInitializer"/></param>
/// <param name="leverage">The requested leverage for this CFD. Default is set by <see cref="SecurityInitializer"/></param>
/// <returns>The new <see cref="Cfd"/> security</returns>
[DocumentationAttribute(AddingData)]
public Cfd AddCfd(string ticker, Resolution? resolution = null, string market = null, bool fillForward = true, decimal leverage = Security.NullLeverage)
@@ -2510,9 +2508,9 @@ namespace QuantConnect.Algorithm
/// <summary>
/// Creates and adds a new <see cref="Index"/> security to the algorithm
/// </summary>
/// <param name="ticker">The currency pair</param>
/// <param name="ticker">The index ticker</param>
/// <param name="resolution">The <see cref="Resolution"/> of market data, Tick, Second, Minute, Hour, or Daily. Default is <see cref="Resolution.Minute"/></param>
/// <param name="market">The index trading market, <seealso cref="Market"/>. Default value is null and looked up using BrokerageModel.DefaultMarkets in <see cref="AddSecurity{T}"/></param>
/// <param name="market">The index trading market, <seealso cref="Market"/>. Default value is null and looked up using <see cref="IBrokerageModel.DefaultMarkets"> in <see cref="AddSecurity{T}"/></param>
/// <param name="fillForward">If true, returns the last available data even if none in that timeslice. Default is <value>true</value></param>
/// <returns>The new <see cref="Index"/> security</returns>
[DocumentationAttribute(AddingData)]
@@ -2525,11 +2523,11 @@ namespace QuantConnect.Algorithm
/// <summary>
/// Creates and adds a new <see cref="Crypto"/> security to the algorithm
/// </summary>
/// <param name="ticker">The currency pair</param>
/// <param name="ticker">The crypto ticker symbol/param>
/// <param name="resolution">The <see cref="Resolution"/> of market data, Tick, Second, Minute, Hour, or Daily. Default is <see cref="Resolution.Minute"/></param>
/// <param name="market">The cfd trading market, <seealso cref="Market"/>. Default value is null and looked up using BrokerageModel.DefaultMarkets in <see cref="AddSecurity{T}"/></param>
/// <param name="market">The The crypto trading market, <seealso cref="Market"/>. Default value is null and looked up using <see cref="IBrokerageModel.DefaultMarkets"/> in <see cref="AddSecurity{T}"/></param>
/// <param name="fillForward">If true, returns the last available data even if none in that timeslice. Default is <value>true</value></param>
/// <param name="leverage">The requested leverage for this equity. Default is set by <see cref="SecurityInitializer"/></param>
/// <param name="leverage">The requested leverage for this crypto. Default is set by <see cref="SecurityInitializer"/></param>
/// <returns>The new <see cref="Crypto"/> security</returns>
[DocumentationAttribute(AddingData)]
public Crypto AddCrypto(string ticker, Resolution? resolution = null, string market = null, bool fillForward = true, decimal leverage = Security.NullLeverage)
@@ -2540,11 +2538,11 @@ namespace QuantConnect.Algorithm
/// <summary>
/// Creates and adds a new <see cref="CryptoFuture"/> security to the algorithm
/// </summary>
/// <param name="ticker">The currency pair</param>
/// <param name="ticker">The crypto future ticker symbol</param>
/// <param name="resolution">The <see cref="Resolution"/> of market data, Tick, Second, Minute, Hour, or Daily. Default is <see cref="Resolution.Minute"/></param>
/// <param name="market">The cfd trading market, <seealso cref="Market"/>. Default value is null and looked up using BrokerageModel.DefaultMarkets in <see cref="AddSecurity{T}"/></param>
/// <param name="market">The The crypto future trading market, <seealso cref="Market"/>. Default value is null and looked up using <see cref="IBrokerageModel.DefaultMarkets"/> in <see cref="AddSecurity{T}"/></param>
/// <param name="fillForward">If true, returns the last available data even if none in that timeslice. Default is <value>true</value></param>
/// <param name="leverage">The requested leverage for this equity. Default is set by <see cref="SecurityInitializer"/></param>
/// <param name="leverage">The requested leverage for this crypto future. Default is set by <see cref="SecurityInitializer"/></param>
/// <returns>The new <see cref="CryptoFuture"/> security</returns>
[DocumentationAttribute(AddingData)]
public CryptoFuture AddCryptoFuture(string ticker, Resolution? resolution = null, string market = null, bool fillForward = true, decimal leverage = Security.NullLeverage)
@@ -2558,7 +2556,7 @@ namespace QuantConnect.Algorithm
/// </summary>
/// <param name="symbol">The symbol of the security to be removed</param>
/// <param name="tag">Optional tag to indicate the cause of removal</param>
/// <remarks>Sugar syntax for <see cref="AddOptionContract"/></remarks>
/// <remarks>Sugar syntax for <see cref="RemoveSecurity"/></remarks>
[DocumentationAttribute(AddingData)]
public bool RemoveOptionContract(Symbol symbol, string tag = null)
{
@@ -2788,7 +2786,7 @@ namespace QuantConnect.Algorithm
public void Debug(string message)
{
if (!_liveMode && (string.IsNullOrEmpty(message) || _previousDebugMessage == message)) return;
_debugMessages.Enqueue(message);
_debugMessages.Enqueue(FormatLog(message));
_previousDebugMessage = message;
}
@@ -2838,7 +2836,7 @@ namespace QuantConnect.Algorithm
public void Log(string message)
{
if (!_liveMode && string.IsNullOrEmpty(message)) return;
_logMessages.Enqueue(message);
_logMessages.Enqueue(FormatLog(message));
}
/// <summary>
@@ -2887,7 +2885,7 @@ namespace QuantConnect.Algorithm
public void Error(string message)
{
if (!_liveMode && (string.IsNullOrEmpty(message) || _previousErrorMessage == message)) return;
_errorMessages.Enqueue(message);
_errorMessages.Enqueue(FormatLog(message));
_previousErrorMessage = message;
}
@@ -2936,10 +2934,7 @@ namespace QuantConnect.Algorithm
[DocumentationAttribute(Logging)]
public void Error(Exception error)
{
var message = error.Message;
if (!_liveMode && (string.IsNullOrEmpty(message) || _previousErrorMessage == message)) return;
_errorMessages.Enqueue(message);
_previousErrorMessage = message;
Error(error.Message);
}
/// <summary>
@@ -3817,5 +3812,10 @@ namespace QuantConnect.Algorithm
var exchange = MarketHoursDatabase.GetExchangeHours(symbol.ID.Market, symbol, symbol.SecurityType);
return UtcTime.ConvertFromUtc(exchange.TimeZone);
}
private string FormatLog(string message)
{
return $"{Time.ToStringInvariant(DateFormat.UI)} {message}";
}
}
}

View File

@@ -4,7 +4,7 @@
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<RootNamespace>QuantConnect.Algorithm</RootNamespace>
<AssemblyName>QuantConnect.Algorithm</AssemblyName>
<TargetFramework>net9.0</TargetFramework>
<TargetFramework>net10.0</TargetFramework>
<SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">..\</SolutionDir>
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
<AnalysisMode>AllEnabledByDefault</AnalysisMode>
@@ -29,7 +29,7 @@
<PackageLicenseFile>LICENSE</PackageLicenseFile>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="QuantConnect.pythonnet" Version="2.0.50" />
<PackageReference Include="QuantConnect.pythonnet" Version="2.0.52" />
<PackageReference Include="MathNet.Numerics" Version="5.0.0" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.2" />
<PackageReference Include="NodaTime" Version="3.0.5" />

View File

@@ -49,7 +49,7 @@ namespace QuantConnect.Algorithm.Framework.Risk
/// Initializes a new instance of the <see cref="CompositeRiskManagementModel"/> class
/// </summary>
/// <param name="riskManagementModels">The individual risk management models defining this composite model</param>
public CompositeRiskManagementModel(IEnumerable<IRiskManagementModel>riskManagementModels)
public CompositeRiskManagementModel(IEnumerable<IRiskManagementModel> riskManagementModels)
{
foreach (var riskManagementModel in riskManagementModels)
{
@@ -129,11 +129,10 @@ namespace QuantConnect.Algorithm.Framework.Risk
/// <param name="pyRiskManagementModel">The risk management model to add</param>
public void AddRiskManagement(PyObject pyRiskManagementModel)
{
IRiskManagementModel riskManagementModel;
if (!pyRiskManagementModel.TryConvert(out riskManagementModel))
{
riskManagementModel = new RiskManagementModelPythonWrapper(pyRiskManagementModel);
}
var riskManagementModel = PythonUtil.CreateInstanceOrWrapper<IRiskManagementModel>(
pyRiskManagementModel,
py => new RiskManagementModelPythonWrapper(py)
);
_riskManagementModels.Add(riskManagementModel);
}
}

View File

@@ -40,6 +40,7 @@ using QuantConnect.Algorithm.Framework.Alphas.Analysis;
using QuantConnect.Commands;
using QuantConnect.Algorithm.Framework.Portfolio.SignalExports;
using QuantConnect.Algorithm.Framework.Execution;
using Common.Util;
namespace QuantConnect.AlgorithmFactory.Python.Wrappers
{
@@ -681,7 +682,7 @@ namespace QuantConnect.AlgorithmFactory.Python.Wrappers
/// <summary>
/// Gets a read-only dictionary with all current parameters
/// </summary>
public IReadOnlyDictionary<string, string> GetParameters() => _baseAlgorithm.GetParameters();
public ReadOnlyExtendedDictionary<string, string> GetParameters() => _baseAlgorithm.GetParameters();
/// <summary>
/// Gets the parameter with the specified name. If a parameter with the specified name does not exist,
@@ -1103,7 +1104,7 @@ namespace QuantConnect.AlgorithmFactory.Python.Wrappers
/// </summary>
/// <param name="symbols">The symbols we want to get seed data for</param>
/// <returns>Securities historical data</returns>
public Dictionary<Symbol, IEnumerable<BaseData>> GetLastKnownPrices(IEnumerable<Symbol> symbols) => _baseAlgorithm.GetLastKnownPrices(symbols);
public DataDictionary<IEnumerable<BaseData>> GetLastKnownPrices(IEnumerable<Symbol> symbols) => _baseAlgorithm.GetLastKnownPrices(symbols);
/// <summary>
/// Set the runtime error

View File

@@ -4,7 +4,7 @@
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<RootNamespace>QuantConnect.AlgorithmFactory</RootNamespace>
<AssemblyName>QuantConnect.AlgorithmFactory</AssemblyName>
<TargetFramework>net9.0</TargetFramework>
<TargetFramework>net10.0</TargetFramework>
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
<OutputPath>bin\$(Configuration)\</OutputPath>
<AnalysisMode>AllEnabledByDefault</AnalysisMode>
@@ -28,7 +28,7 @@
<PackageLicenseFile>LICENSE</PackageLicenseFile>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="QuantConnect.pythonnet" Version="2.0.50" />
<PackageReference Include="QuantConnect.pythonnet" Version="2.0.52" />
<PackageReference Include="NodaTime" Version="3.0.5" />
</ItemGroup>
<ItemGroup>

File diff suppressed because it is too large Load Diff

View File

@@ -15,24 +15,32 @@
using System;
using RestSharp;
using Newtonsoft.Json;
using QuantConnect.Orders;
using QuantConnect.Logging;
using System.Threading.Tasks;
using RestSharp.Authenticators;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Text;
using System.Collections.Generic;
using QuantConnect.Util;
using System.IO;
using System.Threading;
namespace QuantConnect.Api
{
/// <summary>
/// API Connection and Hash Manager
/// </summary>
public class ApiConnection
public class ApiConnection : IDisposable
{
private readonly static JsonSerializerSettings _jsonSettings = new() { Converters = { new LiveAlgorithmResultsJsonConverter(), new OrderJsonConverter() } };
/// <summary>
/// Authorized client to use for requests.
/// </summary>
private HttpClient _httpClient;
/// <summary>
/// Authorized client to use for requests.
/// </summary>
[Obsolete("RestSharp is deprecated and will be removed in a future release. Please use the SetClient method or the request methods that take an HttpRequestMessage")]
public RestClient Client { get; set; }
// Authorization Credentials
@@ -47,10 +55,23 @@ namespace QuantConnect.Api
/// <param name="userId">User Id number from QuantConnect.com account. Found at www.quantconnect.com/account </param>
/// <param name="token">Access token for the QuantConnect account. Found at www.quantconnect.com/account </param>
public ApiConnection(int userId, string token)
: this(userId, token, null)
{
}
/// <summary>
/// Create a new Api Connection Class.
/// </summary>
/// <param name="userId">User Id number from QuantConnect.com account. Found at www.quantconnect.com/account </param>
/// <param name="token">Access token for the QuantConnect account. Found at www.quantconnect.com/account </param>
/// <param name="baseUrl">The client's base address</param>
/// <param name="defaultHeaders">Default headers for the client</param>
/// <param name="timeout">The client timeout in seconds</param>
public ApiConnection(int userId, string token, string baseUrl = null, Dictionary<string, string> defaultHeaders = null, int timeout = 0)
{
_token = token;
_userId = userId.ToStringInvariant();
Client = new RestClient(Globals.Api);
SetClient(!string.IsNullOrEmpty(baseUrl) ? baseUrl : Globals.Api, defaultHeaders, timeout);
}
/// <summary>
@@ -60,16 +81,55 @@ namespace QuantConnect.Api
{
get
{
var request = new RestRequest("authenticate", Method.GET);
AuthenticationResponse response;
if (TryRequest(request, out response))
{
return response.Success;
}
return false;
using var request = new HttpRequestMessage(HttpMethod.Get, "authenticate");
return TryRequest(request, out AuthenticationResponse response) && response.Success;
}
}
/// <summary>
/// Overrides the current client
/// </summary>
/// <param name="baseUrl">The client's base address</param>
/// <param name="defaultHeaders">Default headers for the client</param>
/// <param name="timeout">The client timeout in seconds</param>
public void SetClient(string baseUrl, Dictionary<string, string> defaultHeaders = null, int timeout = 0)
{
if (_httpClient != null)
{
_httpClient.DisposeSafely();
}
_httpClient = new HttpClient() { BaseAddress = new Uri($"{baseUrl.TrimEnd('/')}/") };
Client = new RestClient(baseUrl);
if (defaultHeaders != null)
{
foreach (var header in defaultHeaders)
{
_httpClient.DefaultRequestHeaders.Add(header.Key, header.Value);
}
Client.AddDefaultHeaders(defaultHeaders);
}
if (timeout > 0)
{
_httpClient.Timeout = TimeSpan.FromSeconds(timeout);
Client.Timeout = timeout * 1000;
}
else
{
_httpClient.Timeout = Timeout.InfiniteTimeSpan;
}
}
/// <summary>
/// Disposes of the HTTP client
/// </summary>
public void Dispose()
{
_httpClient.Dispose();
}
/// <summary>
/// Place a secure request and get back an object of type T.
/// </summary>
@@ -77,6 +137,7 @@ namespace QuantConnect.Api
/// <param name="request"></param>
/// <param name="result">Result object from the </param>
/// <returns>T typed object response</returns>
[Obsolete("RestSharp is deprecated and will be removed in a future release. Please use the TryRequest(HttpRequestMessage)")]
public bool TryRequest<T>(RestRequest request, out T result)
where T : RestResponse
{
@@ -90,7 +151,24 @@ namespace QuantConnect.Api
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="request"></param>
/// <param name="result">Result object from the </param>
/// <param name="timeout">Timeout for the request</param>
/// <returns>T typed object response</returns>
public bool TryRequest<T>(HttpRequestMessage request, out T result, TimeSpan? timeout = null)
where T : RestResponse
{
var resultTuple = TryRequestAsync<T>(request, timeout).SynchronouslyAwaitTaskResult();
result = resultTuple.Item2;
return resultTuple.Item1;
}
/// <summary>
/// Place a secure request and get back an object of type T.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="request"></param>
/// <returns>T typed object response</returns>
[Obsolete("RestSharp is deprecated and will be removed in a future release. Please use the TryRequestAsync(HttpRequestMessage)")]
public async Task<Tuple<bool, T>> TryRequestAsync<T>(RestRequest request)
where T : RestResponse
{
@@ -116,7 +194,7 @@ namespace QuantConnect.Api
}
responseContent = restsharpResponse.Content;
result = JsonConvert.DeserializeObject<T>(responseContent, _jsonSettings);
result = responseContent.DeserializeJson<T>();
if (result == null || !result.Success)
{
@@ -133,10 +211,106 @@ namespace QuantConnect.Api
return new Tuple<bool, T>(true, result);
}
/// <summary>
/// Place a secure request and get back an object of type T.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="request"></param>
/// <param name="timeout">Timeout for the request</param>
/// <returns>T typed object response</returns>
public async Task<Tuple<bool, T>> TryRequestAsync<T>(HttpRequestMessage request, TimeSpan? timeout = null)
where T : RestResponse
{
HttpResponseMessage response = null;
Stream responseContentStream = null;
T result = null;
// Default to 100 seconds (since we disabled the default client timeout)
timeout ??= TimeSpan.FromSeconds(100);
try
{
if (request.RequestUri.OriginalString.StartsWith('/'))
{
request.RequestUri = new Uri(request.RequestUri.ToString().TrimStart('/'), UriKind.Relative);
}
SetAuthenticator(request);
// Execute the authenticated REST API Call
using var cancellationTokenSource = new CancellationTokenSource(timeout.Value);
response = await _httpClient.SendAsync(request, cancellationTokenSource.Token).ConfigureAwait(false);
responseContentStream = await response.Content.ReadAsStreamAsync(cancellationTokenSource.Token).ConfigureAwait(false);
result = responseContentStream.DeserializeJson<T>(leaveOpen: true);
if (!response.IsSuccessStatusCode)
{
Log.Error($"ApiConnect.TryRequest({request.RequestUri}): HTTP Error: {(int)response.StatusCode} {response.ReasonPhrase}. " +
$"Content: {GetRawResponseContent(responseContentStream)}");
}
if (result == null || !result.Success)
{
if (Log.DebuggingEnabled)
{
Log.Debug($"ApiConnection.TryRequest({request.RequestUri}): Raw response: '{GetRawResponseContent(responseContentStream)}'");
}
return new Tuple<bool, T>(false, result);
}
}
catch (Exception err)
{
Log.Error($"ApiConnection.TryRequest({request.RequestUri}): Error: {err.Message}, Response content: {GetRawResponseContent(responseContentStream)}");
return new Tuple<bool, T>(false, null);
}
finally
{
response?.DisposeSafely();
responseContentStream?.DisposeSafely();
}
return new Tuple<bool, T>(true, result);
}
private static string GetRawResponseContent(Stream stream)
{
if (stream == null)
{
return string.Empty;
}
try
{
stream.Position = 0;
using var reader = new StreamReader(stream, leaveOpen: true);
return reader.ReadToEnd();
}
catch (Exception)
{
return string.Empty;
}
}
private void SetAuthenticator(RestRequest request)
{
var newTimeStamp = (int)Time.TimeStamp();
var base64EncodedAuthenticationString = GetAuthenticatorHeader(out var timeStamp);
request.AddOrUpdateHeader("Authorization", $"Basic {base64EncodedAuthenticationString}");
request.AddOrUpdateHeader("Timestamp", timeStamp);
}
private void SetAuthenticator(HttpRequestMessage request)
{
request.Headers.Remove("Authorization");
request.Headers.Remove("Timestamp");
var base64EncodedAuthenticationString = GetAuthenticatorHeader(out var timeStamp);
_httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic", base64EncodedAuthenticationString);
request.Headers.Add("Timestamp", timeStamp);
}
private string GetAuthenticatorHeader(out string timeStamp)
{
var newTimeStamp = (int)Time.TimeStamp();
var currentAuth = _authenticator;
if (currentAuth == null || newTimeStamp - currentAuth.TimeStamp > 7000)
{
@@ -144,25 +318,25 @@ namespace QuantConnect.Api
// Add the UTC timestamp to the request header.
// Timestamps older than 7200 seconds will not work.
var hash = Api.CreateSecureHash(newTimeStamp, _token);
var authenticator = new HttpBasicAuthenticator(_userId, hash);
_authenticator = currentAuth = new LeanAuthenticator(authenticator, newTimeStamp);
Client.Authenticator = currentAuth.Authenticator;
var authenticationString = $"{_userId}:{hash}";
var base64EncodedAuthenticationString = Convert.ToBase64String(Encoding.UTF8.GetBytes(authenticationString));
_authenticator = currentAuth = new LeanAuthenticator(newTimeStamp, base64EncodedAuthenticationString);
}
request.AddHeader("Timestamp", currentAuth.TimeStampStr);
timeStamp = currentAuth.TimeStampStr;
return currentAuth.Base64EncodedAuthenticationString;
}
private class LeanAuthenticator
{
public int TimeStamp { get; }
public string TimeStampStr { get; }
public HttpBasicAuthenticator Authenticator { get; }
public LeanAuthenticator(HttpBasicAuthenticator authenticator, int timeStamp)
public string Base64EncodedAuthenticationString { get; }
public LeanAuthenticator(int timeStamp, string base64EncodedAuthenticationString)
{
TimeStamp = timeStamp;
Authenticator = authenticator;
TimeStampStr = timeStamp.ToStringInvariant();
Base64EncodedAuthenticationString = base64EncodedAuthenticationString;
}
}
}

Some files were not shown because too many files have changed in this diff Show More