Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
128 changes: 128 additions & 0 deletions Algorithm.CSharp/DefaultSchedulingSymbolRegressionAlgorithm.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
/*
* 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 QuantConnect.Interfaces;
using System.Collections.Generic;

namespace QuantConnect.Algorithm.CSharp
{
/// <summary>
/// Regression algorithm asserting a default symbol is created using equity market when scheduling if none found
/// </summary>
public class DefaultSchedulingSymbolRegressionAlgorithm : QCAlgorithm, IRegressionAlgorithmDefinition
{
private bool _implicitChecked;
private bool _explicitChecked;

/// <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(2013, 10, 07);
SetEndDate(2013, 10, 11);

// implicitly figured usa equity
Schedule.On(DateRules.Tomorrow, TimeRules.AfterMarketOpen("AAPL"), () =>
{
_implicitChecked = true;
if (Time.TimeOfDay != new TimeSpan(9, 30, 0))
{
throw new RegressionTestException($"Unexpected time of day {Time.TimeOfDay}");
}
});

// picked up from cache
AddIndex("SPX");
Schedule.On(DateRules.Tomorrow, TimeRules.BeforeMarketClose("SPX", extendedMarketClose: true), () =>
{
_explicitChecked = true;
if (Time.TimeOfDay != new TimeSpan(16, 15, 0))
{
throw new RegressionTestException($"Unexpected time of day {Time.TimeOfDay}");
}
});
}

public override void OnEndOfAlgorithm()
{
if (!_explicitChecked || !_implicitChecked)
{
throw new RegressionTestException("Failed to run expected checks!");
}
}

/// <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 => 43;

/// <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", "-8.91"},
{"Tracking Error", "0.223"},
{"Treynor Ratio", "0"},
{"Total Fees", "$0.00"},
{"Estimated Strategy Capacity", "$0"},
{"Lowest Capacity Asset", ""},
{"Portfolio Turnover", "0%"},
{"Drawdown Recovery", "0"},
{"OrderListHash", "d41d8cd98f00b204e9800998ecf8427e"}
};
}
}
44 changes: 44 additions & 0 deletions Algorithm.Python/DefaultSchedulingSymbolRegressionAlgorithm.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
# 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>
### Regression algorithm asserting a default symbol is created using equity market when scheduling if none found
### </summary>
class DefaultSchedulingSymbolRegressionAlgorithm(QCAlgorithm):
def initialize(self):
'''Initialise the data and resolution required, as well as the cash and start-end dates for your algorithm. All algorithms must initialized.'''
self.set_start_date(2013, 10, 7)
self.set_end_date(2013, 10, 11)

# implicitly figured usa equity
self.schedule.on(self.date_rules.tomorrow, self.time_rules.after_market_open("AAPL"), self._implicit_check)

# picked up from cache
self.add_index("SPX")
self.schedule.on(self.date_rules.tomorrow, self.time_rules.before_market_close("SPX", extended_market_close = True), self._explicit_check)

def _implicit_check(self):
self._implicitChecked = True
if self.time.time() != time(9, 30, 0):
raise RegressionTestException(f"Unexpected time of day {self.time.time()}")

def _explicit_check(self):
self._explicitChecked = True
if self.time.time() != time(16, 15, 0):
raise RegressionTestException(f"Unexpected time of day {self.time.time()}")

def on_end_of_algorithm(self):
if not self._explicitChecked or not self._implicitChecked:
raise RegressionTestException("Failed to run expected checks!")
3 changes: 1 addition & 2 deletions Algorithm/QCAlgorithm.cs
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,6 @@
using Newtonsoft.Json;
using QuantConnect.Securities.Index;
using QuantConnect.Api;
using System.Threading.Tasks;

namespace QuantConnect.Algorithm
{
Expand Down Expand Up @@ -224,7 +223,7 @@ public QCAlgorithm()
UniverseSettings = new UniverseSettings(Resolution.Minute, Security.NullLeverage, true, false, TimeSpan.FromDays(1));

// initialize our scheduler, this acts as a liason to the real time handler
Schedule = new ScheduleManager(Securities, TimeZone, MarketHoursDatabase);
Schedule = new ScheduleManager(this, Securities, TimeZone, MarketHoursDatabase);

// initialize the trade builder
SetTradeBuilder(new TradeBuilder(FillGroupingMethod.FillToFill, FillMatchingMethod.FIFO));
Expand Down
27 changes: 25 additions & 2 deletions Common/Scheduling/BaseScheduleRules.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
*/

using NodaTime;
using QuantConnect.Interfaces;
using QuantConnect.Securities;

namespace QuantConnect.Scheduling
Expand All @@ -24,6 +25,9 @@ namespace QuantConnect.Scheduling
/// </summary>
public class BaseScheduleRules
{
private bool _sentImplicitWarning;
private readonly IAlgorithm _algorithm;

/// <summary>
/// The algorithm's default time zone
/// </summary>
Expand All @@ -42,13 +46,15 @@ public class BaseScheduleRules
/// <summary>
/// Initializes a new instance of the <see cref="TimeRules"/> helper class
/// </summary>
/// <param name="algorithm">The algorithm instance</param>
/// <param name="securities">The security manager</param>
/// <param name="timeZone">The algorithm's default time zone</param>
/// <param name="marketHoursDatabase">The market hours database instance to use</param>
public BaseScheduleRules(SecurityManager securities, DateTimeZone timeZone, MarketHoursDatabase marketHoursDatabase)
public BaseScheduleRules(IAlgorithm algorithm, SecurityManager securities, DateTimeZone timeZone, MarketHoursDatabase marketHoursDatabase)
{
Securities = securities;
TimeZone = timeZone;
_algorithm = algorithm;
Securities = securities;
MarketHoursDatabase = marketHoursDatabase;
}

Expand All @@ -63,5 +69,22 @@ protected SecurityExchangeHours GetSecurityExchangeHours(Symbol symbol)
}
return security.Exchange.Hours;
}

protected Symbol GetSymbol(string ticker)
{
if (SymbolCache.TryGetSymbol(ticker, out var symbolCache))
{
return symbolCache;
}

if (!_sentImplicitWarning)
{
_sentImplicitWarning = true;
_algorithm?.Debug($"Warning: no existing symbol found for ticker {ticker}, it will be created with {SecurityType.Equity} type.");
}
symbolCache = Symbol.Create(ticker, SecurityType.Equity, Market.USA);
SymbolCache.Set(ticker, symbolCache);
return symbolCache;
}
}
}
79 changes: 75 additions & 4 deletions Common/Scheduling/DateRules.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
using NodaTime;
using System.Linq;
using System.Globalization;
using QuantConnect.Interfaces;
using QuantConnect.Securities;
using System.Collections.Generic;

Expand All @@ -31,11 +32,12 @@ public class DateRules : BaseScheduleRules
/// <summary>
/// Initializes a new instance of the <see cref="DateRules"/> helper class
/// </summary>
/// <param name="algorithm">The algorithm instance</param>
/// <param name="securities">The security manager</param>
/// <param name="timeZone">The algorithm's default time zone</param>
/// <param name="marketHoursDatabase">The market hours database instance to use</param>
public DateRules(SecurityManager securities, DateTimeZone timeZone, MarketHoursDatabase marketHoursDatabase)
: base(securities, timeZone, marketHoursDatabase)
public DateRules(IAlgorithm algorithm, SecurityManager securities, DateTimeZone timeZone, MarketHoursDatabase marketHoursDatabase)
: base(algorithm, securities, timeZone, marketHoursDatabase)
{
}

Expand Down Expand Up @@ -118,6 +120,14 @@ public IDateRule EveryDay()
return new FuncDateRule("EveryDay", Time.EachDay);
}

/// <summary>
/// Specifies an event should fire every day the symbol is trading
/// </summary>
/// <param name="symbol">The symbol whose exchange is used to determine tradable dates</param>
/// <param name="extendedMarketHours">True to include days with extended market hours only, like sunday for futures</param>
/// <returns>A date rule that fires every day the specified symbol trades</returns>
public IDateRule EveryDay(string symbol, bool extendedMarketHours = false) => EveryDay(GetSymbol(symbol), extendedMarketHours);

/// <summary>
/// Specifies an event should fire every day the symbol is trading
/// </summary>
Expand All @@ -137,9 +147,19 @@ public IDateRule EveryDay(Symbol symbol, bool extendedMarketHours = false)
/// <returns>A date rule that fires on the first of each year + offset</returns>
public IDateRule YearStart(int daysOffset = 0)
{
return YearStart(null, daysOffset, false);
return YearStart((Symbol)null, daysOffset, false);
}

/// <summary>
/// Specifies an event should fire on the first tradable date + offset for the specified symbol of each year
/// </summary>
/// <param name="symbol">The symbol whose exchange is used to determine the first tradable date of the year</param>
/// <param name="daysOffset"> The amount of tradable days to offset the schedule by; must be between 0 and 365</param>
/// <param name="extendedMarketHours">True to include days with extended market hours only, like sunday for futures</param>
/// <returns>A date rule that fires on the first tradable date + offset for the
/// specified security each year</returns>
public IDateRule YearStart(string symbol, int daysOffset = 0, bool extendedMarketHours = true) => YearStart(GetSymbol(symbol), daysOffset, extendedMarketHours);

/// <summary>
/// Specifies an event should fire on the first tradable date + offset for the specified symbol of each year
/// </summary>
Expand Down Expand Up @@ -173,9 +193,18 @@ public IDateRule YearStart(Symbol symbol, int daysOffset = 0, bool extendedMarke
/// <returns>A date rule that fires on the last of each year - offset</returns>
public IDateRule YearEnd(int daysOffset = 0)
{
return YearEnd(null, daysOffset, false);
return YearEnd((Symbol)null, daysOffset, false);
}

/// <summary>
/// Specifies an event should fire on the last tradable date - offset for the specified symbol of each year
/// </summary>
/// <param name="symbol">The symbol whose exchange is used to determine the last tradable date of the year</param>
/// <param name="daysOffset">The amount of tradable days to offset the schedule by; must be between 0 and 365.</param>
/// <param name="extendedMarketHours">True to include days with extended market hours only, like sunday for futures</param>
/// <returns>A date rule that fires on the last tradable date - offset for the specified security each year</returns>
public IDateRule YearEnd(string symbol, int daysOffset = 0, bool extendedMarketHours = true) => YearEnd(GetSymbol(symbol), daysOffset, extendedMarketHours);

/// <summary>
/// Specifies an event should fire on the last tradable date - offset for the specified symbol of each year
/// </summary>
Expand Down Expand Up @@ -211,6 +240,16 @@ public IDateRule MonthStart(int daysOffset = 0)
return new FuncDateRule(GetName(null, "MonthStart", daysOffset), (start, end) => MonthIterator(null, start, end, daysOffset, true, false));
}

/// <summary>
/// Specifies an event should fire on the first tradable date + offset for the specified symbol of each month
/// </summary>
/// <param name="symbol">The symbol whose exchange is used to determine the first tradable date of the month</param>
/// <param name="daysOffset"> The amount of tradable days to offset the schedule by; must be between 0 and 30</param>
/// <param name="extendedMarketHours">True to include days with extended market hours only, like sunday for futures</param>
/// <returns>A date rule that fires on the first tradable date + offset for the
/// specified security each month</returns>
public IDateRule MonthStart(string symbol, int daysOffset = 0, bool extendedMarketHours = true) => MonthStart(GetSymbol(symbol), daysOffset, extendedMarketHours);

/// <summary>
/// Specifies an event should fire on the first tradable date + offset for the specified symbol of each month
/// </summary>
Expand Down Expand Up @@ -241,6 +280,15 @@ public IDateRule MonthEnd(int daysOffset = 0)
return new FuncDateRule(GetName(null, "MonthEnd", -daysOffset), (start, end) => MonthIterator(null, start, end, daysOffset, false, false));
}

/// <summary>
/// Specifies an event should fire on the last tradable date - offset for the specified symbol of each month
/// </summary>
/// <param name="symbol">The symbol whose exchange is used to determine the last tradable date of the month</param>
/// <param name="daysOffset">The amount of tradable days to offset the schedule by; must be between 0 and 30.</param>
/// <param name="extendedMarketHours">True to include days with extended market hours only, like sunday for futures</param>
/// <returns>A date rule that fires on the last tradable date - offset for the specified security each month</returns>
public IDateRule MonthEnd(string symbol, int daysOffset = 0, bool extendedMarketHours = true) => MonthEnd(GetSymbol(symbol), daysOffset, extendedMarketHours);

/// <summary>
/// Specifies an event should fire on the last tradable date - offset for the specified symbol of each month
/// </summary>
Expand Down Expand Up @@ -276,6 +324,18 @@ public IDateRule WeekStart(int daysOffset = 0)
return new FuncDateRule(GetName(null, "WeekStart", daysOffset), (start, end) => WeekIterator(null, start, end, daysOffset, true, false));
}

/// <summary>
/// Specifies an event should fire on the first tradable date + offset for the specified
/// symbol each week
/// </summary>
/// <param name="symbol">The symbol whose exchange is used to determine the first
/// tradeable date of the week</param>
/// <param name="daysOffset">The amount of tradable days to offset the first tradable day by</param>
/// <param name="extendedMarketHours">True to include extended market hours, false otherwise</param>
/// <returns>A date rule that fires on the first + offset tradable date for the specified
/// security each week</returns>
public IDateRule WeekStart(string symbol, int daysOffset = 0, bool extendedMarketHours = true) => WeekStart(GetSymbol(symbol), daysOffset, extendedMarketHours);

/// <summary>
/// Specifies an event should fire on the first tradable date + offset for the specified
/// symbol each week
Expand Down Expand Up @@ -320,6 +380,17 @@ public IDateRule WeekEnd(int daysOffset = 0)
return new FuncDateRule(GetName(null, "WeekEnd", -daysOffset), (start, end) => WeekIterator(null, start, end, daysOffset, false, false));
}

/// <summary>
/// Specifies an event should fire on the last - offset tradable date for the specified
/// symbol of each week
/// </summary>
/// <param name="symbol">The symbol whose exchange is used to determine the last
/// tradable date of the week</param>
/// <param name="daysOffset"> The amount of tradable days to offset the last tradable day by each week</param>
/// <param name="extendedMarketHours">True to include extended market hours, false otherwise</param>
/// <returns>A date rule that fires on the last - offset tradable date for the specified security each week</returns>
public IDateRule WeekEnd(string symbol, int daysOffset = 0, bool extendedMarketHours = true) => WeekEnd(GetSymbol(symbol), daysOffset, extendedMarketHours);

/// <summary>
/// Specifies an event should fire on the last - offset tradable date for the specified
/// symbol of each week
Expand Down
Loading
Loading