GeezerVisonThe World Wide Web, restored to 800 pixels of glory. |
| Home|About|Gaming cabinet|Archives|How it works|Starter sites |
GeezerVison is showing github.com — Lean/Algorithm/QCAlgorithm.Python.cs at master · QuantConnect/Lean Expand file tree/ Copy pathQCAlgorithm.Python.csMore file actions 2148 lines (1965 loc) · 120 KB / Copy pathQCAlgorithm.Python.csFile metadata and controls2148 lines (1965 loc) · 120 KB 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 /* * 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.Consolidators; using QuantConnect.Data.Market; using QuantConnect.Indicators; using System; using QuantConnect.Securities; using NodaTime; using System.Collections.Generic; using QuantConnect.Python; using Python.Runtime; using QuantConnect.Data.UniverseSelection; using QuantConnect.Data.Fundamental; using System.Linq; using Newtonsoft.Json; using QuantConnect.Brokerages; using QuantConnect.Scheduling; using QuantConnect.Util; using QuantConnect.Interfaces; using QuantConnect.Orders; using QuantConnect.Commands; using QuantConnect.Api; namespace QuantConnect.Algorithm { public partial class QCAlgorithm { private readonly Dictionary<IntPtr, PythonIndicator> _pythonIndicators = new Dictionary<IntPtr, PythonIndicator>(); /// <summary> /// PandasConverter for this Algorithm /// </summary> public virtual PandasConverter PandasConverter { get; private set; } /// <summary> /// Sets pandas converter /// </summary> public void SetPandasConverter() { PandasConverter = new PandasConverter(); } /// <summary> /// AddData a new user defined data source, requiring only the minimum config options. /// The data is added with a default time zone of NewYork (Eastern Daylight Savings Time). /// This method is meant for custom data types that require a ticker, but have no underlying Symbol. /// Examples of data sources that meet this criteria are U.S. Treasury Yield Curve Rates and Trading Economics data /// </summary> /// <param name="type">Data source type</param> /// <param name="ticker">Key/Ticker for data</param> /// <param name="resolution">Resolution of the data</param> /// <returns>The new <see cref="Security"/></returns> [DocumentationAttribute(AddingData)] public Security AddData(PyObject type, string ticker, Resolution? resolution = null) { return AddData(type, ticker, resolution, null, false, 1m); } /// <summary> /// AddData a new user defined data source, requiring only the minimum config options. /// The data is added with a default time zone of NewYork (Eastern Daylight Savings Time). /// This adds a Symbol to the `Underlying` property in the custom data Symbol object. /// Use this method when adding custom data with a ticker from the past, such as "AOL" /// before it became "TWX", or if you need to filter using custom data and place trades on the /// Symbol associated with the custom data. /// </summary> /// <param name="type">Data source type</param> /// <param name="underlying">The underlying symbol for the custom data</param> /// <param name="resolution">Resolution of the data</param> /// <returns>The new <see cref="Security"/></returns> /// <remarks> /// We include three optional unused object parameters so that pythonnet chooses the intended method /// correctly. Previously, calling the overloaded method that accepts a string would instead call this method. /// Adding the three unused parameters makes it choose the correct method when using a string or Symbol. This is /// due to pythonnet's method precedence, as viewable here: https://github.com/QuantConnect/pythonnet/blob/9e29755c54e6008cb016e3dd9d75fbd8cd19fcf7/src/runtime/methodbinder.cs#L215 /// </remarks> [DocumentationAttribute(AddingData)] public Security AddData(PyObject type, Symbol underlying, Resolution? resolution = null) { return AddData(type, underlying, resolution, null, false, 1m); } /// <summary> /// AddData a new user defined data source, requiring only the minimum config options. /// This method is meant for custom data types that require a ticker, but have no underlying Symbol. /// Examples of data sources that meet this criteria are U.S. Treasury Yield Curve Rates and Trading Economics data /// </summary> /// <param name="type">Data source type</param> /// <param name="ticker">Key/Ticker for data</param> /// <param name="resolution">Resolution of the Data Required</param> /// <param name="timeZone">Specifies the time zone of the raw data</param> /// <param name="fillForward">When no data available on a tradebar, return the last data that was generated</param> /// <param name="leverage">Custom leverage per security</param> /// <returns>The new <see cref="Security"/></returns> [DocumentationAttribute(AddingData)] public Security AddData(PyObject type, string ticker, Resolution? resolution, DateTimeZone timeZone, bool fillForward = false, decimal leverage = 1.0m) { return AddData(GetCustomDataType(type), ticker, resolution, timeZone, fillForward, leverage); } /// <summary> /// AddData a new user defined data source, requiring only the minimum config options. /// This adds a Symbol to the `Underlying` property in the custom data Symbol object. /// Use this method when adding custom data with a ticker from the past, such as "AOL" /// before it became "TWX", or if you need to filter using custom data and place trades on the /// Symbol associated with the custom data. /// </summary> /// <param name="type">Data source type</param> /// <param name="underlying">The underlying symbol for the custom data</param> /// <param name="resolution">Resolution of the Data Required</param> /// <param name="timeZone">Specifies the time zone of the raw data</param> /// <param name="fillForward">When no data available on a tradebar, return the last data that was generated</param> /// <param name="leverage">Custom leverage per security</param> /// <returns>The new <see cref="Security"/></returns> /// <remarks> /// We include three optional unused object parameters so that pythonnet chooses the intended method /// correctly. Previously, calling the overloaded method that accepts a string would instead call this method. /// Adding the three unused parameters makes it choose the correct method when using a string or Symbol. This is /// due to pythonnet's method precedence, as viewable here: https://github.com/QuantConnect/pythonnet/blob/9e29755c54e6008cb016e3dd9d75fbd8cd19fcf7/src/runtime/methodbinder.cs#L215 /// </remarks> [DocumentationAttribute(AddingData)] public Security AddData(PyObject type, Symbol underlying, Resolution? resolution, DateTimeZone timeZone, bool fillForward = false, decimal leverage = 1.0m) { return AddData(GetCustomDataType(type), underlying, resolution, timeZone, fillForward, leverage); } /// <summary> /// AddData a new user defined data source, requiring only the minimum config options. /// This method is meant for custom data types that require a ticker, but have no underlying Symbol. /// Examples of data sources that meet this criteria are U.S. Treasury Yield Curve Rates and Trading Economics data /// </summary> /// <param name="dataType">Data source type</param> /// <param name="ticker">Key/Ticker for data</param> /// <param name="resolution">Resolution of the Data Required</param> /// <param name="timeZone">Specifies the time zone of the raw data</param> /// <param name="fillForward">When no data available on a tradebar, return the last data that was generated</param> /// <param name="leverage">Custom leverage per security</param> /// <returns>The new <see cref="Security"/></returns> [DocumentationAttribute(AddingData)] public Security AddData(Type dataType, string ticker, Resolution? resolution, DateTimeZone timeZone, bool fillForward = false, decimal leverage = 1.0m) { // NOTE: Invoking methods on BaseData w/out setting the symbol may provide unexpected behavior var baseInstance = dataType.GetBaseDataInstance(); if (!baseInstance.RequiresMapping()) { var symbol = new Symbol( SecurityIdentifier.GenerateBase(dataType, ticker, Market.USA, baseInstance.RequiresMapping()), ticker); return AddDataImpl(dataType, symbol, resolution, timeZone, fillForward, leverage); } // If we need a mappable ticker and we can't find one in the SymbolCache, throw Symbol underlying; if (!SymbolCache.TryGetSymbol(ticker, out underlying)) { throw new InvalidOperationException($"The custom data type {dataType.Name} requires mapping, but the provided ticker is not in the cache. " + $"Please add this custom data type using a Symbol or perform this call after " + $"a Security has been added using AddEquity, AddForex, AddCfd, AddCrypto, AddFuture, AddOption or AddSecurity. " + $"An example use case can be found in CustomDataAddDataRegressionAlgorithm"); } return AddData(dataType, underlying, resolution, timeZone, fillForward, leverage); } /// <summary> /// AddData a new user defined data source, requiring only the minimum config options. /// This adds a Symbol to the `Underlying` property in the custom data Symbol object. /// Use this method when adding custom data with a ticker from the past, such as "AOL" /// before it became "TWX", or if you need to filter using custom data and place trades on the /// Symbol associated with the custom data. /// </summary> /// <param name="dataType">Data source type</param> /// <param name="underlying"></param> /// <param name="resolution">Resolution of the Data Required</param> /// <param name="timeZone">Specifies the time zone of the raw data</param> /// <param name="fillForward">When no data available on a tradebar, return the last data that was generated</param> /// <param name="leverage">Custom leverage per security</param> /// <returns>The new <see cref="Security"/></returns> /// <remarks> /// We include three optional unused object parameters so that pythonnet chooses the intended method /// correctly. Previously, calling the overloaded method that accepts a string would instead call this method. /// Adding the three unused parameters makes it choose the correct method when using a string or Symbol. This is /// due to pythonnet's method precedence, as viewable here: https://github.com/QuantConnect/pythonnet/blob/9e29755c54e6008cb016e3dd9d75fbd8cd19fcf7/src/runtime/methodbinder.cs#L215 /// </remarks> [DocumentationAttribute(AddingData)] public Security AddData(Type dataType, Symbol underlying, Resolution? resolution = null, DateTimeZone timeZone = null, bool fillForward = false, decimal leverage = 1.0m) { var symbol = QuantConnect.Symbol.CreateBase(dataType, underlying, underlying.ID.Market); return AddDataImpl(dataType, symbol, resolution, timeZone, fillForward, leverage); } /// <summary> /// AddData a new user defined data source including symbol properties and exchange hours, /// all other vars are not required and will use defaults. /// This overload reflects the C# equivalent for custom properties and market hours /// </summary> /// <param name="type">Data source type</param> /// <param name="ticker">Key/Ticker for data</param> /// <param name="properties">The properties of this new custom data</param> /// <param name="exchangeHours">The Exchange hours of this symbol</param> /// <param name="resolution">Resolution of the Data Required</param> /// <param name="fillForward">When no data available on a tradebar, return the last data that was generated</param> /// <param name="leverage">Custom leverage per security</param> /// <returns>The new <see cref="Security"/></returns> [DocumentationAttribute(AddingData)] public Security AddData(PyObject type, string ticker, SymbolProperties properties, SecurityExchangeHours exchangeHours, Resolution? resolution = null, bool fillForward = false, decimal leverage = 1.0m) { // Get the right key for storage of base type symbols var dataType = GetCustomDataType(type); var key = SecurityIdentifier.GenerateBaseSymbol(dataType, ticker); // Add entries to our Symbol Properties DB and MarketHours DB SetDatabaseEntries(key, properties, exchangeHours); // Then add the data return AddData(dataType, ticker, resolution, null, fillForward, leverage); } /// <summary> /// Creates and adds a new Future Option contract to the algorithm. /// </summary> /// <param name="futureSymbol">The Future canonical symbol (i.e. Symbol returned from <see cref="AddFuture"/>)</param> /// <param name="optionFilter">Filter to apply to option contracts loaded as part of the universe</param> /// <returns>The new Option security, containing a Future as its underlying.</returns> /// <exception cref="ArgumentException">The symbol provided is not canonical.</exception> [DocumentationAttribute(AddingData)] public void AddFutureOption(Symbol futureSymbol, PyObject optionFilter) { Func<OptionFilterUniverse, OptionFilterUniverse> optionFilterUniverse; if (!optionFilter.TrySafeAs(out optionFilterUniverse)) { throw new ArgumentException("Option contract universe filter provided is not a function"); } AddFutureOption(futureSymbol, optionFilterUniverse); } /// <summary> /// Adds the provided final Symbol with/without underlying set to the algorithm. /// This method is meant for custom data types that require a ticker, but have no underlying Symbol. /// Examples of data sources that meet this criteria are U.S. Treasury Yield Curve Rates and Trading Economics data /// </summary> /// <param name="dataType">Data source type</param> /// <param name="symbol">Final symbol that includes underlying (if any)</param> /// <param name="resolution">Resolution of the Data required</param> /// <param name="timeZone">Specifies the time zone of the raw data</param> /// <param name="fillForward">When no data available on a tradebar, return the last data that was generated</param> /// <param name="leverage">Custom leverage per security</param> /// <returns>The new <see cref="Security"/></returns> private Security AddDataImpl(Type dataType, Symbol symbol, Resolution? resolution, DateTimeZone timeZone, bool fillForward, decimal leverage) { var alias = symbol.ID.Symbol; SymbolCache.Set(alias, symbol); if (timeZone != null) { // user set time zone MarketHoursDatabase.SetEntryAlwaysOpen(symbol.ID.Market, alias, SecurityType.Base, timeZone); } //Add this new generic data as a tradeable security: var config = SubscriptionManager.SubscriptionDataConfigService.Add( dataType, symbol, resolution, fillForward, isCustomData: true, extendedMarketHours: true); var security = Securities.CreateSecurity(symbol, config, leverage, addToSymbolCache: false); return AddToUserDefinedUniverse(security, new List<SubscriptionDataConfig> { config }); } /// <summary> /// Resolves the custom data <see cref="Type"/> from the PyObject argument of <see cref="AddData(PyObject, string, Resolution?)"/> and overloads, /// throwing a clear exception if the caller passed something other than a custom data class (e.g. a string ticker). /// </summary> private static Type GetCustomDataType(PyObject type) { if (type.TryCreateType(out var dataType)) { return dataType; } using var _ = Py.GIL(); throw new ArgumentException(Messages.QCAlgorithm.AddDataInvalidPyObjectType(type.Repr())); } /// <summary> /// Creates a new universe and adds it to the algorithm. This is for coarse fundamental US Equity data and /// will be executed on day changes in the NewYork time zone (<see cref="TimeZones.NewYork"/>) /// </summary> /// <param name="pyObject">Defines an initial coarse selection</param> [DocumentationAttribute(Universes)] public Universe AddUniverse(PyObject pyObject) { Func<IEnumerable<Fundamental>, object> fundamentalSelector; Universe universe; if (pyObject.TryCreateType(out var type)) { return AddUniverse(pyObject, null, null); } // TODO: to be removed when https://github.com/QuantConnect/pythonnet/issues/62 is solved else if (pyObject.TryConvert(out universe)) { return AddUniverse(universe); } else if (pyObject.TryConvert(out universe, allowPythonDerivative: true)) { return AddUniverse(new UniversePythonWrapper(pyObject)); } else if (pyObject.TrySafeAs(out fundamentalSelector)) { return AddUniverse(FundamentalUniverse.USA(fundamentalSelector)); } else { using (Py.GIL()) { throw new ArgumentException($"QCAlgorithm.AddUniverse: {pyObject.Repr()} is not a valid argument."); } } } /// <summary> /// Creates a new universe and adds it to the algorithm. This is for coarse and fine fundamental US Equity data and /// will be executed on day changes in the NewYork time zone (<see cref="TimeZones.NewYork"/>) /// </summary> /// <param name="pyObject">Defines an initial coarse selection or a universe</param> /// <param name="pyfine">Defines a more detailed selection with access to more data</param> [DocumentationAttribute(Universes)] public Universe AddUniverse(PyObject pyObject, PyObject pyfine) { Func<IEnumerable<CoarseFundamental>, object> coarseFunc; Func<IEnumerable<FineFundamental>, object> fineFunc; try { // this is due to a pythonNet limitation even if defining 'AddUniverse(IDateRule, PyObject)' // it will chose this method instead IDateRule dateRule; using (Py.GIL()) { dateRule = pyObject.As<IDateRule>(); } if (pyfine.TrySafeAs(out coarseFunc)) { return AddUniverse(dateRule, coarseFunc.ConvertToUniverseSelectionSymbolDelegate()); } } catch (InvalidCastException) { // pass } if (pyObject.TryCreateType(out var type)) { return AddUniverse(pyObject, null, pyfine); } else if (pyObject.TryConvert(out Universe universe) && pyfine.TrySafeAs(out fineFunc)) { return AddUniverse(universe, fineFunc.ConvertToUniverseSelectionSymbolDelegate()); } else if (pyObject.TrySafeAs(out coarseFunc) && pyfine.TrySafeAs(out fineFunc)) { return AddUniverse(coarseFunc.ConvertToUniverseSelectionSymbolDelegate(), fineFunc.ConvertToUniverseSelectionSymbolDelegate()); } else { using (Py.GIL()) { throw new ArgumentException($"QCAlgorithm.AddUniverse: {pyObject.Repr()} or {pyfine.Repr()} is not a valid argument."); } } } /// <summary> /// Creates a new universe and adds it to the algorithm. This can be used to return a list of string /// symbols retrieved from anywhere and will loads those symbols under the US Equity market. /// </summary> /// <param name="name">A unique name for this universe</param> /// <param name="resolution">The resolution this universe should be triggered on</param> /// <param name="pySelector">Function delegate that accepts a DateTime and returns a collection of string symbols</param> [DocumentationAttribute(Universes)] public Universe AddUniverse(string name, Resolution resolution, PyObject pySelector) { var selector = pySelector.SafeAs<Func<DateTime, object>>(); return AddUniverse(name, resolution, selector.ConvertToUniverseSelectionStringDelegate()); } /// <summary> /// Creates a new universe and adds it to the algorithm. This can be used to return a list of string /// symbols retrieved from anywhere and will loads those symbols under the US Equity market. /// </summary> /// <param name="name">A unique name for this universe</param> /// <param name="pySelector">Function delegate that accepts a DateTime and returns a collection of string symbols</param> [DocumentationAttribute(Universes)] public Universe AddUniverse(string name, PyObject pySelector) { var selector = pySelector.SafeAs<Func<DateTime, object>>(); return AddUniverse(name, selector.ConvertToUniverseSelectionStringDelegate()); } /// <summary> /// Creates a new user defined universe that will fire on the requested resolution during market hours. /// </summary> /// <param name="securityType">The security type of the universe</param> /// <param name="name">A unique name for this universe</param> /// <param name="resolution">The resolution this universe should be triggered on</param> /// <param name="market">The market of the universe</param> /// <param name="universeSettings">The subscription settings used for securities added from this universe</param> /// <param name="pySelector">Function delegate that accepts a DateTime and returns a collection of string symbols</param> [DocumentationAttribute(Universes)] public Universe AddUniverse(SecurityType securityType, string name, Resolution resolution, string market, UniverseSettings universeSettings, PyObject pySelector) { var selector = pySelector.SafeAs<Func<DateTime, object>>(); return AddUniverse(securityType, name, resolution, market, universeSettings, selector.ConvertToUniverseSelectionStringDelegate()); } /// <summary> /// Creates a new universe and adds it to the algorithm. This will use the default universe settings /// specified via the <see cref="UniverseSettings"/> property. This universe will use the defaults /// of SecurityType.Equity, Resolution.Daily, Market.USA, and UniverseSettings /// </summary> /// <param name="T">The data type</param> /// <param name="name">A unique name for this universe</param> /// <param name="selector">Function delegate that performs selection on the universe data</param> [DocumentationAttribute(Universes)] public Universe AddUniverse(PyObject T, string name, PyObject selector) { return AddUniverse(T.CreateType(), null, name, null, null, null, selector); } /// <summary> /// Creates a new universe and adds it to the algorithm. This will use the default universe settings /// specified via the <see cref="UniverseSettings"/> property. This universe will use the defaults /// of SecurityType.Equity, Market.USA and UniverseSettings /// </summary> /// <param name="T">The data type</param> /// <param name="name">A unique name for this universe</param> /// <param name="resolution">The expected resolution of the universe data</param> /// <param name="selector">Function delegate that performs selection on the universe data</param> [DocumentationAttribute(Universes)] public Universe AddUniverse(PyObject T, string name, Resolution resolution, PyObject selector) { return AddUniverse(T.CreateType(), null, name, resolution, null, null, selector); } /// <summary> /// Creates a new universe and adds it to the algorithm. This will use the default universe settings /// specified via the <see cref="UniverseSettings"/> property. This universe will use the defaults /// of SecurityType.Equity, and Market.USA /// </summary> /// <param name="T">The data type</param> /// <param name="name">A unique name for this universe</param> /// <param name="resolution">The expected resolution of the universe data</param> /// <param name="universeSettings">The settings used for securities added by this universe</param> /// <param name="selector">Function delegate that performs selection on the universe data</param> [DocumentationAttribute(Universes)] public Universe AddUniverse(PyObject T, string name, Resolution resolution, UniverseSettings universeSettings, PyObject selector) { return AddUniverse(T.CreateType(), null, name, resolution, null, universeSettings, selector); } /// <summary> /// Creates a new universe and adds it to the algorithm. This will use the default universe settings /// specified via the <see cref="UniverseSettings"/> property. This universe will use the defaults /// of SecurityType.Equity, Resolution.Daily, and Market.USA /// </summary> /// <param name="T">The data type</param> /// <param name="name">A unique name for this universe</param> /// <param name="universeSettings">The settings used for securities added by this universe</param> /// <param name="selector">Function delegate that performs selection on the universe data</param> [DocumentationAttribute(Universes)] public Universe AddUniverse(PyObject T, string name, UniverseSettings universeSettings, PyObject selector) { return AddUniverse(T.CreateType(), null, name, null, null, universeSettings, selector); } /// <summary> /// Creates a new universe and adds it to the algorithm. This will use the default universe settings /// specified via the <see cref="UniverseSettings"/> property. /// </summary> /// <param name="T">The data type</param> /// <param name="securityType">The security type the universe produces</param> /// <param name="name">A unique name for this universe</param> /// <param name="resolution">The expected resolution of the universe data</param> /// <param name="market">The market for selected symbols</param> /// <param name="selector">Function delegate that performs selection on the universe data</param> [DocumentationAttribute(Universes)] public Universe AddUniverse(PyObject T, SecurityType securityType, string name, Resolution resolution, string market, PyObject selector) { return AddUniverse(T.CreateType(), securityType, name, resolution, market, null, selector); } /// <summary> /// Creates a new universe and adds it to the algorithm /// </summary> /// <param name="T">The data type</param> /// <param name="securityType">The security type the universe produces</param> /// <param name="name">A unique name for this universe</param> /// <param name="resolution">The expected resolution of the universe data</param> /// <param name="market">The market for selected symbols</param> /// <param name="universeSettings">The subscription settings to use for newly created subscriptions</param> /// <param name="selector">Function delegate that performs selection on the universe data</param> [DocumentationAttribute(Universes)] public Universe AddUniverse(PyObject T, SecurityType securityType, string name, Resolution resolution, string market, UniverseSettings universeSettings, PyObject selector) { return AddUniverse(T.CreateType(), securityType, name, resolution, market, universeSettings, selector); } /// <summary> /// Creates a new universe and adds it to the algorithm /// </summary> /// <param name="dataType">The data type</param> /// <param name="securityType">The security type the universe produces</param> /// <param name="name">A unique name for this universe</param> /// <param name="resolution">The expected resolution of the universe data</param> /// <param name="market">The market for selected symbols</param> /// <param name="universeSettings">The subscription settings to use for newly created subscriptions</param> /// <param name="pySelector">Function delegate that performs selection on the universe data</param> [DocumentationAttribute(Universes)] public Universe AddUniverse(Type dataType, SecurityType? securityType = null, string name = null, Resolution? resolution = null, string market = null, UniverseSettings universeSettings = null, PyObject pySelector = null) { if (market.IsNullOrEmpty()) { market = Market.USA; } securityType ??= SecurityType.Equity; Func<IEnumerable<BaseData>, IEnumerable<Symbol>> wrappedSelector = null; if (pySelector != null) { var selector = pySelector.SafeAs<Func<IEnumerable<IBaseData>, object>>(); wrappedSelector = baseDatas => { var result = selector(baseDatas); if (ReferenceEquals(result, Universe.Unchanged)) { return Universe.Unchanged; } return ((object[])result).Select(x => x is Symbol symbol ? symbol : QuantConnect.Symbol.Create((string)x, securityType.Value, market, baseDataType: dataType)); }; } return AddUniverseSymbolSelector(dataType, name, resolution, market, universeSettings, wrappedSelector); } /// <summary> /// Creates a new universe selection model and adds it to the algorithm. This universe selection model will chain to the security /// changes of a given <see cref="Universe"/> selection output and create a new <see cref="OptionChainUniverse"/> for each of them /// </summary> /// <param name="universe">The universe we want to chain an option universe selection model too</param> /// <param name="optionFilter">The option filter universe to use</param> [DocumentationAttribute(Universes)] public void AddUniverseOptions(PyObject universe, PyObject optionFilter) { Func<OptionFilterUniverse, OptionFilterUniverse> convertedOptionChain; Universe universeToChain; if (universe.TryConvert(out universeToChain) && optionFilter.TrySafeAs(out convertedOptionChain)) { AddUniverseOptions(universeToChain, convertedOptionChain); } else { using (Py.GIL()) { throw new ArgumentException($"QCAlgorithm.AddChainedEquityOptionUniverseSelectionModel: {universe.Repr()} or {optionFilter.Repr()} is not a valid argument."); } } } /// <summary> /// Registers the consolidator to receive automatic updates as well as configures the indicator to receive updates /// from the consolidator. /// </summary> /// <param name="symbol">The symbol to register against</param> /// <param name="indicator">The indicator to receive data from the consolidator</param> /// <param name="resolution">The resolution at which to send data to the indicator, null to use the same resolution as the subscription</param> /// <param name="selector">Selects a value from the BaseData send into the indicator, if null defaults to a cast (x => (T)x)</param> [DocumentationAttribute(Indicators)] [DocumentationAttribute(ConsolidatingData)] public void RegisterIndicator(Symbol symbol, PyObject indicator, Resolution? resolution = null, PyObject selector = null) { RegisterIndicator(symbol, indicator, ResolveConsolidator(symbol, resolution), selector); } /// <summary> /// Registers the consolidator to receive automatic updates as well as configures the indicator to receive updates /// from the consolidator. /// </summary> /// <param name="symbol">The symbol to register against</param> /// <param name="indicator">The indicator to receive data from the consolidator</param> /// <param name="resolution">The resolution at which to send data to the indicator, null to use the same resolution as the subscription</param> /// <param name="selector">Selects a value from the BaseData send into the indicator, if null defaults to a cast (x => (T)x)</param> [DocumentationAttribute(Indicators)] [DocumentationAttribute(ConsolidatingData)] public void RegisterIndicator(Symbol symbol, PyObject indicator, TimeSpan? resolution = null, PyObject selector = null) { RegisterIndicator(symbol, indicator, ResolveConsolidator(symbol, resolution), selector); } /// <summary> /// Registers the consolidator to receive automatic updates as well as configures the indicator to receive updates /// from the consolidator. /// </summary> /// <param name="symbol">The symbol to register against</param> /// <param name="indicator">The indicator to receive data from the consolidator</param> /// <param name="pyObject">The python object that it is trying to register with, could be consolidator or a timespan</param> /// <param name="selector">Selects a value from the BaseData send into the indicator, if null defaults to a cast (x => (T)x)</param> [DocumentationAttribute(Indicators)] [DocumentationAttribute(ConsolidatingData)] public void RegisterIndicator(Symbol symbol, PyObject indicator, PyObject pyObject, PyObject selector = null) { // First check if this is just a regular IDataConsolidator IDataConsolidator dataConsolidator; if (pyObject.TryConvert(out dataConsolidator)) { RegisterIndicator(symbol, indicator, dataConsolidator, selector); return; } try { dataConsolidator = new DataConsolidatorPythonWrapper(pyObject); } catch { // Finally, since above didn't work, just try it as a timespan // Issue #4668 Fix using (Py.GIL()) { try { // tryConvert does not work for timespan TimeSpan? timeSpan = pyObject.SafeAs<TimeSpan>(); if (timeSpan != default(TimeSpan)) { RegisterIndicator(symbol, indicator, timeSpan, selector); return; } } catch (Exception e) { throw new ArgumentException("Invalid third argument, should be either a valid consolidator or timedelta object. The following exception was thrown: ", e); } } } RegisterIndicator(symbol, indicator, dataConsolidator, selector); } /// <summary> /// Registers the consolidator to receive automatic updates as well as configures the indicator to receive updates /// from the consolidator. /// </summary> /// <param name="symbol">The symbol to register against</param> /// <param name="indicator">The indicator to receive data from the consolidator</param> /// <param name="consolidator">The consolidator to receive raw subscription data</param> /// <param name="selector">Selects a value from the BaseData send into the indicator, if null defaults to a cast (x => (T)x)</param> [DocumentationAttribute(Indicators)] [DocumentationAttribute(ConsolidatingData)] public void RegisterIndicator(Symbol symbol, PyObject indicator, IDataConsolidator consolidator, PyObject selector = null) { // TODO: to be removed when https://github.com/QuantConnect/pythonnet/issues/62 is solved var convertedIndicator = ConvertPythonIndicator(indicator); switch (convertedIndicator) { case PythonIndicator pythonIndicator: RegisterIndicator(symbol, pythonIndicator, consolidator, selector?.SafeAs<Func<IBaseData, IBaseData>>()); break; case IndicatorBase<IndicatorDataPoint> dataPointIndicator: RegisterIndicator(symbol, dataPointIndicator, consolidator, selector?.SafeAs<Func<IBaseData, decimal>>()); break; case IndicatorBase<IBaseDataBar> baseDataBarIndicator: RegisterIndicator(symbol, baseDataBarIndicator, consolidator, selector?.SafeAs<Func<IBaseData, IBaseDataBar>>()); break; case IndicatorBase<TradeBar> tradeBarIndicator: RegisterIndicator(symbol, tradeBarIndicator, consolidator, selector?.SafeAs<Func<IBaseData, TradeBar>>()); break; case IndicatorBase<IBaseData> baseDataIndicator: RegisterIndicator(symbol, baseDataIndicator, consolidator, selector?.SafeAs<Func<IBaseData, IBaseData>>()); break; case IndicatorBase<BaseData> baseDataIndicator: RegisterIndicator(symbol, baseDataIndicator, consolidator, selector?.SafeAs<Func<IBaseData, BaseData>>()); break; default: // Shouldn't happen, ConvertPythonIndicator will wrap the PyObject in a PythonIndicator instance if it can't convert it throw new ArgumentException($"Indicator type {indicator.GetPythonType().Name} is not supported."); } } /// <summary> /// Warms up a given indicator with historical data /// </summary> /// <param name="symbol">The symbol whose indicator we want</param> /// <param name="indicator">The indicator we want to warm up</param> /// <param name="resolution">The resolution</param> /// <param name="selector">Selects a value from the BaseData send into the indicator, if null defaults to a cast (x => (T)x)</param> [DocumentationAttribute(Indicators)] [DocumentationAttribute(HistoricalData)] public void WarmUpIndicator(Symbol symbol, PyObject indicator, Resolution? resolution = null, PyObject selector = null) { // TODO: to be removed when https://github.com/QuantConnect/pythonnet/issues/62 is solved WarmUpIndicator([symbol], indicator, resolution, selector); } /// <summary> /// Warms up a given indicator with historical data /// </summary> /// <param name="symbol">The symbol or symbols to retrieve historical data for</param> /// <param name="indicator">The indicator we want to warm up</param> /// <param name="resolution">The resolution</param> /// <param name="selector">Selects a value from the BaseData send into the indicator, if null defaults to a cast (x => (T)x)</param> [DocumentationAttribute(Indicators)] [DocumentationAttribute(HistoricalData)] public void WarmUpIndicator(PyObject symbol, PyObject indicator, Resolution? resolution = null, PyObject selector = null) { // TODO: to be removed when https://github.com/QuantConnect/pythonnet/issues/62 is solved var symbols = symbol.ConvertToSymbolEnumerable(); WarmUpIndicator(symbols, indicator, resolution, selector); } /// <summary> /// Warms up a given indicator with historical data /// </summary> /// <param name="symbols">The symbols to retrieve historical data for</param> /// <param name="indicator">The indicator we want to warm up</param> /// <param name="resolution">The resolution</param> /// <param name="selector">Selects a value from the BaseData send into the indicator, if null defaults to a cast (x => (T)x)</param> private void WarmUpIndicator(IEnumerable<Symbol> symbols, PyObject indicator, Resolution? resolution = null, PyObject selector = null) { // TODO: to be removed when https://github.com/QuantConnect/pythonnet/issues/62 is solved var convertedIndicator = ConvertPythonIndicator(indicator); switch (convertedIndicator) { case PythonIndicator pythonIndicator: WarmUpIndicator(symbols, pythonIndicator, resolution, selector?.SafeAs<Func<IBaseData, IBaseData>>()); break; case IndicatorBase<IndicatorDataPoint> dataPointIndicator: WarmUpIndicator(symbols, dataPointIndicator, resolution, selector?.SafeAs<Func<IBaseData, decimal>>()); break; case IndicatorBase<IBaseDataBar> baseDataBarIndicator: WarmUpIndicator(symbols, baseDataBarIndicator, resolution, selector?.SafeAs<Func<IBaseData, IBaseDataBar>>()); break; case IndicatorBase<TradeBar> tradeBarIndicator: WarmUpIndicator(symbols, tradeBarIndicator, resolution, selector?.SafeAs<Func<IBaseData, TradeBar>>()); break; case IndicatorBase<IBaseData> baseDataIndicator: WarmUpIndicator(symbols, baseDataIndicator, resolution, selector?.SafeAs<Func<IBaseData, IBaseData>>()); break; case IndicatorBase<BaseData> baseDataIndicator: WarmUpIndicator(symbols, baseDataIndicator, resolution, selector?.SafeAs<Func<IBaseData, BaseData>>()); break; default: // Shouldn't happen, ConvertPythonIndicator will wrap the PyObject in a PythonIndicator instance if it can't convert it throw new ArgumentException($"Indicator type {indicator.GetPythonType().Name} is not supported."); } } /// <summary> /// Warms up a given indicator with historical data /// </summary> /// <param name="symbol">The symbol whose indicator we want</param> /// <param name="indicator">The indicator we want to warm up</param> /// <param name="period">The necessary period to warm up the indicator</param> /// <param name="selector">Selects a value from the BaseData send into the indicator, if null defaults to a cast (x => (T)x)</param> [DocumentationAttribute(Indicators)] [DocumentationAttribute(HistoricalData)] public void WarmUpIndicator(Symbol symbol, PyObject indicator, TimeSpan period, PyObject selector = null) { WarmUpIndicator([symbol], indicator, period, selector); } /// <summary> /// Warms up a given indicator with historical data /// </summary> /// <param name="symbol">The symbol or symbols to retrieve historical data for</param> /// <param name="indicator">The indicator we want to warm up</param> /// <param name="period">The necessary period to warm up the indicator</param> /// <param name="selector">Selects a value from the BaseData send into the indicator, if null defaults to a cast (x => (T)x)</param> [DocumentationAttribute(Indicators)] [DocumentationAttribute(HistoricalData)] public void WarmUpIndicator(PyObject symbol, PyObject indicator, TimeSpan period, PyObject selector = null) { var symbols = symbol.ConvertToSymbolEnumerable(); WarmUpIndicator(symbols, indicator, period, selector); } /// <summary> /// Warms up a given indicator with historical data /// </summary> /// <param name="symbols">The symbols to retrieve historical data for</param> /// <param name="indicator">The indicator we want to warm up</param> /// <param name="period">The necessary period to warm up the indicator</param> /// <param name="selector">Selects a value from the BaseData send into the indicator, if null defaults to a cast (x => (T)x)</param> private void WarmUpIndicator(IEnumerable<Symbol> symbols, PyObject indicator, TimeSpan period, PyObject selector = null) { var convertedIndicator = ConvertPythonIndicator(indicator); switch (convertedIndicator) { case PythonIndicator pythonIndicator: WarmUpIndicator(symbols, pythonIndicator, period, selector?.SafeAs<Func<IBaseData, IBaseData>>()); break; case IndicatorBase<IndicatorDataPoint> dataPointIndicator: WarmUpIndicator(symbols, dataPointIndicator, period, selector?.SafeAs<Func<IBaseData, decimal>>()); break; case IndicatorBase<IBaseDataBar> baseDataBarIndicator: WarmUpIndicator(symbols, baseDataBarIndicator, period, selector?.SafeAs<Func<IBaseData, IBaseDataBar>>()); break; case IndicatorBase<TradeBar> tradeBarIndicator: WarmUpIndicator(symbols, tradeBarIndicator, period, selector?.SafeAs<Func<IBaseData, TradeBar>>()); break; case IndicatorBase<IBaseData> baseDataIndicator: WarmUpIndicator(symbols, baseDataIndicator, period, selector?.SafeAs<Func<IBaseData, IBaseData>>()); break; case IndicatorBase<BaseData> baseDataIndicator: WarmUpIndicator(symbols, baseDataIndicator, period, selector?.SafeAs<Func<IBaseData, BaseData>>()); break; default: // Shouldn't happen, ConvertPythonIndicator will wrap the PyObject in a PythonIndicator instance if it can't convert it throw new ArgumentException($"Indicator type {indicator.GetPythonType().Name} is not supported."); } } /// <summary> /// Plot a chart using string series name, with value. /// </summary> /// <param name="series">Name of the plot series</param> /// <param name="pyObject">PyObject with the value to plot</param> /// <seealso cref="Plot(string,decimal)"/> [DocumentationAttribute(Charting)] public void Plot(string series, PyObject pyObject) { using (Py.GIL()) { if (pyObject.TryConvert(out IndicatorBase indicator, true)) { Plot(series, indicator); } else { try { var value = (((dynamic)pyObject).Value as PyObject).GetAndDispose<decimal>(); Plot(series, value); } catch { var pythonType = pyObject.GetPythonType().Repr(); throw new ArgumentException($"QCAlgorithm.Plot(): The last argument should be a QuantConnect Indicator object, {pythonType} was provided."); } } } } /// <summary> /// Plots the value of each indicator on the chart /// </summary> /// <param name="chart">The chart's name</param> /// <param name="first">The first indicator to plot</param> /// <param name="second">The second indicator to plot</param> /// <param name="third">The third indicator to plot</param> /// <param name="fourth">The fourth indicator to plot</param> /// <seealso cref="Plot(string,string,decimal)"/> [DocumentationAttribute(Charting)] public void Plot(string chart, Indicator first, Indicator second = null, Indicator third = null, Indicator fourth = null) { Plot(chart, new[] { first, second, third, fourth }.Where(x => x != null).ToArray()); } /// <summary> /// Plots the value of each indicator on the chart /// </summary> /// <param name="chart">The chart's name</param> /// <param name="first">The first indicator to plot</param> /// <param name="second">The second indicator to plot</param> /// <param name="third">The third indicator to plot</param> /// <param name="fourth">The fourth indicator to plot</param> /// <seealso cref="Plot(string,string,decimal)"/> [DocumentationAttribute(Charting)] public void Plot(string chart, BarIndicator first, BarIndicator second = null, BarIndicator third = null, BarIndicator fourth = null) { Plot(chart, new[] { first, second, third, fourth }.Where(x => x != null).ToArray()); } /// <summary> /// Plots the value of each indicator on the chart /// </summary> /// <param name="chart">The chart's name</param> /// <param name="first">The first indicator to plot</param> /// <param name="second">The second indicator to plot</param> /// <param name="third">The third indicator to plot</param> /// <param name="fourth">The fourth indicator to plot</param> /// <seealso cref="Plot(string,string,decimal)"/> [DocumentationAttribute(Charting)] public void Plot(string chart, TradeBarIndicator first, TradeBarIndicator second = null, TradeBarIndicator third = null, TradeBarIndicator fourth = null) { Plot(chart, new[] { first, second, third, fourth }.Where(x => x != null).ToArray()); } /// <summary> /// Automatically plots each indicator when a new value is available /// </summary> [DocumentationAttribute(Charting)] [DocumentationAttribute(Indicators)] public void PlotIndicator(string chart, PyObject first, PyObject second = null, PyObject third = null, PyObject fourth = null) { var array = GetIndicatorArray(first, second, third, fourth); PlotIndicator(chart, array[0], array[1], array[2], array[3]); } /// <summary> /// Automatically plots each indicator when a new value is available /// </summary> [DocumentationAttribute(Charting)] [DocumentationAttribute(Indicators)] public void PlotIndicator(string chart, bool waitForReady, PyObject first, PyObject second = null, PyObject third = null, PyObject fourth = null) { var array = GetIndicatorArray(first, second, third, fourth); PlotIndicator(chart, waitForReady, array[0], array[1], array[2], array[3]); } /// <summary> /// Creates a new FilteredIdentity indicator for the symbol The indicator will be automatically /// updated on the symbol's subscription resolution /// </summary> /// <param name="symbol">The symbol whose values we want as an indicator</param> /// <param name="selector">Selects a value from the BaseData, if null defaults to the .Value property (x => x.Value)</param> /// <param name="filter">Filters the IBaseData send into the indicator, if null defaults to true (x => true) which means no filter</param> /// <param name="fieldName">The name of the field being selected</param> /// <returns>A new FilteredIdentity indicator for the specified symbol and selector</returns> [DocumentationAttribute(Indicators)] public FilteredIdentity FilteredIdentity(Symbol symbol, PyObject selector = null, PyObject filter = null, string fieldName = null) { var resolution = GetSubscription(symbol).Resolution; return FilteredIdentity(symbol, resolution, selector, filter, fieldName); } /// <summary> /// Creates a new FilteredIdentity indicator for the symbol The indicator will be automatically /// updated on the symbol's subscription resolution /// </summary> /// <param name="symbol">The symbol whose values we want as an indicator</param> /// <param name="resolution">The desired resolution of the data</param> /// <param name="selector">Selects a value from the BaseData, if null defaults to the .Value property (x => x.Value)</param> /// <param name="filter">Filters the IBaseData send into the indicator, if null defaults to true (x => true) which means no filter</param> /// <param name="fieldName">The name of the field being selected</param> /// <returns>A new FilteredIdentity indicator for the specified symbol and selector</returns> [DocumentationAttribute(Indicators)] public FilteredIdentity FilteredIdentity(Symbol symbol, Resolution resolution, PyObject selector = null, PyObject filter = null, string fieldName = null) { var name = CreateIndicatorName(symbol, fieldName ?? "close", resolution); var pyselector = PythonUtil.ToFunc<IBaseData, IBaseDataBar>(selector); var filteredIdentity = new FilteredIdentity(name, filter); RegisterIndicator(symbol, filteredIdentity, resolution, pyselector); return filteredIdentity; } /// <summary> /// Creates a new FilteredIdentity indicator for the symbol The indicator will be automatically |
| You are visitor 01402503 — GeezerVison does not store the pages you look up. Best viewed with Netscape Navigator 4.7 or Internet Explorer 6 at 800×600. No cookies required. |