book
Checkout our new book! Hands on AI Trading with Python, QuantConnect, and AWS Learn More arrow

RegAlytics

US Regulatory Alerts - Financial Sector

Introduction

The US Regulatory Alerts dataset by RegAlytics tracks changes from over 8,000 globally governing bodies. The data covers over 2.5 million alerts, starts from January 2020, and is delivered on a daily basis. This dataset is created by sourcing information from over 8,000 regulators and using proprietary technology to gather and structure the regulatory data. Once prepared, the data is thoroughly reviewed by RegAlytics' team of regulatory experts and delivered each morning by 8AM for industry use.

This dataset depends on the US Equity Security Master dataset because the US Equity Security Master dataset contains information on splits, dividends, and symbol changes.

For more information about the US Regulatory Alerts - Financial Sector dataset, including CLI commands and pricing, see the dataset listing.

About the Provider

RegAlytics was founded by Mary Kopczynski, Aaron Heisler, Alexander Appugliese, and Werner Pauliks in 2019 with the goal of significantly reducing the time and cost required to mitigate regulatory risk. RegAlytics provides access to accurate and clean regulatory data from all global regulators in all sectors that is enriched by regulatory experts for risk and compliance teams everywhere. Please come to RegAlytics directly if you would like data on other sectors or countries!

Getting Started

The following snippet demonstrates how to request data from the US Regulatory Alerts - Financial Sector dataset:

from QuantConnect.DataSource import *

self.dataset_symbol = self.add_data(RegalyticsRegulatoryArticles, "REG").symbol
using QuantConnect.DataSource;

_datasetSymbol = AddData<RegalyticsRegulatoryArticles>("REG").Symbol;

Data Summary

The following table describes the dataset properties:

PropertyValue
Start DateJanuary 2020
Coverage2,500,000 Alerts
Data DensitySparse
ResolutionDaily
TimezoneNew York

Requesting Data

To add US Regulatory Alerts data to your algorithm, call the AddDataadd_data method. Save a reference to the dataset Symbol so you can access the data later in your algorithm.

class RegalyticsDataAlgorithm(QCAlgorithm):
    def initialize(self) -> None:
        self.set_start_date(2021, 1, 1)
        self.set_end_date(2021, 6, 1)
        self.set_cash(100000)
        
        self.dataset_symbol = self.add_data(RegalyticsRegulatoryArticles, "REG").symbol
namespace QuantConnect
{
    public class RegalyticsDataAlgorithm : QCAlgorithm
    {
        private Symbol _datasetSymbol;
        
        public override void Initialize()
        {
            SetStartDate(2021, 1, 1);
            SetEndDate(2021, 6, 1);
            SetCash(100000);
            
            _datasetSymbol = AddData<RegalyticsRegulatoryArticles>("REG").Symbol;
        }
    }
}

Accessing Data

To get the current US Regulatory Alerts data, index the current Slice with the dataset Symbol. Slice objects deliver unique events to your algorithm as they happen, but the Slice may not contain data for your dataset at every time step. To avoid issues, check if the Slice contains the data you want before you index it.

def on_data(self, slice: Slice) -> None:
    if slice.contains_key(self.dataset_symbol):
        data_points = slice[self.dataset_symbol]
        for data_point in data_points:
            self.log(f"{self.dataset_symbol} title at {slice.time}: {data_point.title}")
public override void OnData(Slice slice)
{
    if (slice.ContainsKey(_datasetSymbol))
    {
        var dataPoints = slice[_datasetSymbol];
        foreach (var dataPoint in dataPoints)
        {
            Log($"{_datasetSymbol} title at {slice.Time}: {dataPoint.Title}");
        }
    }
}

To iterate through all of the dataset objects in the current Slice, call the Getget method.

def on_data(self, slice: Slice) -> None:
    data = slice.get(RegalyticsRegulatoryArticles)
    if data:
        for articles in data.values():
            self.log(f"{self.time} {articles.to_string()}")
            
            for article in articles:
                self.log(f"{self.dataset_symbol} article title at {slice.time}: {article.title}")
public override void OnData(Slice slice)
{
    var data = slice.Get<RegalyticsRegulatoryArticles>();
    if (!data.IsNullOrEmpty())
    {
        foreach (var articles in data.Values)
        {
            Log($"{Time} {articles.ToString()}");
            foreach (RegalyticsRegulatoryArticle article in articles)
            {
                Log($"{_datasetSymbol} article title at {slice.Time}: {article.Title}");
            }
        }
    }
}

Historical Data

To get historical US Regulatory Alerts data, call the Historyhistory method with the dataset Symbol. If there is no data in the period you request, the history result is empty.

# DataFrame where the columns are the RegalyticsRegulatoryArticle attributes:
history_df = self.history(self.dataset_symbol, 100, Resolution.DAILY, flatten=True)

# Series where the values are lists of RegalyticsRegulatoryArticle objects: 
history_series = self.history(self.dataset_symbol, 100, Resolution.DAILY)

# Dataset objects:
history_bars =  self.history[RegalyticsRegulatoryArticles](self.dataset_symbol, 100, Resolution.DAILY)
var history = History<RegalyticsRegulatoryArticles>(_datasetSymbol, 100, Resolution.Daily);

Remove Subscriptions

To remove your subscription to US Regulatory Alerts data, call the RemoveSecurityremove_security method.

self.remove_security(self.dataset_symbol)
RemoveSecurity(_datasetSymbol);

Example Applications

This regulatory dataset enables you to accurately design strategies while mitigating regulatory risk. Examples include the following strategies:

Classic Algorithm Example

The following example algorithm sells short 100% SPY if any predetermined negative sentimental phrase was present in any of the previous day's regulatory articles. Otherwise, it buys and hold 100% SPY.

from AlgorithmImports import *
from QuantConnect.DataSource import *

class RegalyticsDataAlgorithm(QCAlgorithm): 
    # Pre-defined list of negative sentiment phrases as indicator for short selling, since these words will decrease confident in equity performance
    negative_sentiment_phrases = ["emergency rule", "proposed rule change", "development of rulemaking"]
    
    def initialize(self) -> None:
        self.set_start_date(2022, 7, 10)
        self.set_end_date(2022, 7, 15)
        self.set_cash(100000)
        
        self.spy = self.add_equity("SPY", Resolution.DAILY).symbol
            
        # Requesting data to receive updated regulatory news for timely short selling
        self.regalytics_symbol = self.add_data(RegalyticsRegulatoryArticles, "REG").symbol
            
        # Historical data for past articles
        history = self.history(self.regalytics_symbol, 7, Resolution.DAILY)
        self.debug(f"We got {len(history)} items from our history request")

    def on_data(self, slice: Slice) -> None:
        # Only trade on regulatory news data
        data = slice.Get(RegalyticsRegulatoryArticles)
        if data:
            for articles in data.values():
                self.log(articles.to_string())
                # If any of the negative phrases appeared in regulatory news, we expect a market drop for the day
                if any([p in article.title.lower() for p in self.negative_sentiment_phrases for article in articles]):
                    self.set_holdings(self.spy, -1)
                else:
                    self.set_holdings(self.spy, 1)
using QuantConnect.DataSource;

namespace QuantConnect
{
    public class RegalyticsDataAlgorithm : QCAlgorithm
    {
        // Pre-defined list of negative sentiment phrases as indicator for short selling, since these words will decrease confident in equity performance
        private readonly string[] _negativeSentimentPhrases = new [] {"emergency rule", "proposed rule change", "development of rulemaking"};
        private Symbol _symbol, _regalyticsSymbol; 
        
        public override void Initialize()
        {
            SetStartDate(2022, 7, 10);
            SetEndDate(2022, 7, 15);
            SetCash(100000);
            
            _symbol = AddEquity("SPY", Resolution.Daily).Symbol;
            
            // Requesting data to receive updated regulatory news for timely short selling
            _regalyticsSymbol = AddData<RegalyticsRegulatoryArticles>("REG").Symbol;
            
            // Historical data for past articles
            var history = History<RegalyticsRegulatoryArticles>(_regalyticsSymbol, 7, Resolution.Daily);
            Debug($"We got {history.Count()} items from our history request");
        }

        public override void OnData(Slice slice)
        {
            // Only trade on regulatory news data
            var data = slice.Get<RegalyticsRegulatoryArticles>();
            if (!data.IsNullOrEmpty())
            {
                foreach (var articles in data.Values)
                {
                    Log($"{Time} {articles.ToString()}");
                    // If any of the negative phrases appeared in regulatory news, we expect a market drop for the day
                    if (_negativeSentimentPhrases.Any(p => articles.Any(x => 
                        ((RegalyticsRegulatoryArticle) x).Title.ToLower().Contains(p))))
                    {
                        SetHoldings(_symbol, -1);
                    }
                    else
                    {
                        SetHoldings(_symbol, 1);
                    }
                }
            }
        }
    }
}

Framework Algorithm Example

The following example algorithm buys and holds the S&P 500 ETF, SPY. To reduce regulatory risk, it liquidates your holdings for 2 days following regulatory announcements regarding new rules.

from AlgorithmImports import *
from QuantConnect.DataSource import *
from QuantConnect.Data.UniverseSelection import *

class RegalyticsDataAlgorithm(QCAlgorithm):
    
    def initialize(self) -> None:
        self.set_start_date(2021, 1, 1)
        self.set_end_date(2021, 6, 1)
        self.set_cash(100000) 
        
        self.universe_settings.resolution = Resolution.DAILY
        # Trade SPY as the proxy of the whole equity market movement on the regulatory news
        symbols = [ Symbol.create("SPY", SecurityType.EQUITY, Market.USA) ]
        self.add_universe_selection(ManualUniverseSelectionModel(symbols))
        
        self.add_alpha(RegAnalyticsAlphaModel(self))
        
        self.set_portfolio_construction(EqualWeightingPortfolioConstructionModel(lambda time: None))
        
        self.add_risk_management(NullRiskManagementModel())
        
        self.set_execution(ImmediateExecutionModel())

                
class RegAnalyticsAlphaModel(AlphaModel):
    
    symbols = []
    last_news_date = datetime.min
    target_direction = InsightDirection.UP
    # Pre-defined list of negative sentiment phrases as indicator for short selling, since these words will decrease confident in equity performance
    negative_sentiment_phrases = ["emergency rule", "proposed rule change", "development of rulemaking"]
    # Assuming the negative impact of the regulatory news will last for 2 days
    news_affect_duration = timedelta(days = 2)
    
    def __init__(self, algorithm: QCAlgorithm) -> None:
        # Requesting data to receive updated regulatory news for timely short selling
        self.regalytics_symbol = algorithm.add_data(RegalyticsRegulatoryArticles, "REG").symbol
        
        # Historical data for past articles
        history = algorithm.history(self.regalytics_symbol, 14, Resolution.DAILY)
        algorithm.debug(f"We got {len(history)} from our history request")


    def update(self, algorithm: QCAlgorithm, slice: Slice) -> List[Insight]:
        insights = []

        # Only trade on regulatory news data
        if slice.contains_key(self.regalytics_symbol) and slice[self.regalytics_symbol] is not None:
            articles = slice[self.regalytics_symbol]
            title = [article.title.lower() for article in articles]

            # If any of the negative phrases appeared in regulatory news, we expect a market drop for the day
            # Signal an exit from the market when regulatory articles with negative sentiment are released
            for phrase in self.negative_sentiment_phrases:
                if any(phrase in title):
                    self.target_direction = InsightDirection.FLAT
                    self.last_news_date = slice.time
        
        
        # Signal an entry if we've waited long enough for the market to digest the negative news
        if self.last_news_date + self.news_affect_duration < slice.time:
            self.target_direction = InsightDirection.UP
        
        for symbol in self.symbols:
            # Ensure we have security data in the current Slice to avoid stale fill
            if not (slice.contains_key(symbol) and slice[symbol] is not None):
                continue
            
            if self.target_direction == InsightDirection.UP and not algorithm.portfolio[symbol].invested:
                insights += [Insight.price(symbol, timedelta(days=90), InsightDirection.UP)]
            elif self.target_direction == InsightDirection.FLAT and algorithm.portfolio[symbol].invested:
                insights += [Insight.price(symbol, self.news_affect_duration, InsightDirection.FLAT)]
        
        return insights
        
        
    def on_securities_changed(self, algorithm: QCAlgorithm, changes: SecurityChanges) -> None:
        for security in changes.added_securities:
            self.symbols.append(security.symbol)
        
        for security in changes.removed_securities:
            symbol = security.symbol
            if symbol in self.symbols:
                self.symbols.remove(symbol)
using QuantConnect.DataSource;
using QuantConnect.Data.UniverseSelection;

namespace QuantConnect
{
    public class RegalyticsDataAlgorithm : QCAlgorithm
    {
        public override void Initialize()
        {
            SetStartDate(2021, 1, 1);
            SetEndDate(2021, 6, 1);
            SetCash(100000);
            
            UniverseSettings.Resolution = Resolution.Daily;
            //  Trade SPY as the proxy of the whole equity market movement on the regulatory news
            AddUniverseSelection(
                new ManualUniverseSelectionModel(
                    QuantConnect.Symbol.Create("SPY", SecurityType.Equity, Market.USA)
            ));
            
            AddAlpha(new RegAnalyticsAlphaModel(this));
            
            SetPortfolioConstruction(new EqualWeightingPortfolioConstructionModel(time => None));
            
            AddRiskManagement(new NullRiskManagementModel());
            
            SetExecution(new ImmediateExecutionModel());
        }
        
        public class RegAnalyticsAlphaModel : AlphaModel
        {
            private List<Symbol> _symbols = new List<Symbol>();
            private Symbol _regalyticsSymbol;
            private DateTime _lastNewsDate = DateTime.MinValue;
            private InsightDirection _targetDirection = InsightDirection.Up;
            // Pre-defined list of negative sentiment phrases as indicator for short selling, since these words will decrease confident in equity performance
            private string[] _negativeSentimentPhrases = new string[] {"emergency rule", "proposed rule change", "development of rulemaking"};
            // Assuming the negative impact of the regulatory news will last for 2 days
            private TimeSpan _newsAffectDuration = TimeSpan.FromDays(2);
             
            public RegAnalyticsAlphaModel(QCAlgorithm algorithm)
            {
                // Requesting data to receive updated regulatory news for timely short selling
                _regalyticsSymbol = algorithm.AddData<RegalyticsRegulatoryArticles>("REG").Symbol;
                
                // Historical data for past articles
                var history = algorithm.History<RegalyticsRegulatoryArticles>(_regalyticsSymbol, 14, Resolution.Daily);
                algorithm.Debug($"We got {history.Count()} items from our history request");
            }
    
            public override IEnumerable<Insight> Update(QCAlgorithm algorithm, Slice slice)
            {
                var insights = new List<Insight>();

                // Only trade on regulatory news data
                if (slice.ContainsKey(_regalyticsSymbol) && slice[_regalyticsSymbol] != None)
                {
                    var articles = slice[_regalyticsSymbol];
                    foreach (RegalyticsRegulatoryArticle article in articles)
                    {
                        // If any of the negative phrases appeared in regulatory news, we expect a market drop for the day
                        // Signal an exit from the market when regulatory articles with negative sentiment are released
                        if (_negativeSentimentPhrases.Any(x => article.Title.Contains(x)))
                        {
                            _targetDirection = InsightDirection.Flat;
                            _lastNewsDate = slice.Time;
                        }
                    }
                }
                
                // Signal an entry if we've waited long enough for the market to digest the negative news
                if (_lastNewsDate + _newsAffectDuration < slice.Time)
                {
                    _targetDirection = InsightDirection.Up;
                }
                
                foreach (var symbol in _symbols)
                {
                    // Ensure we have security data in the current Slice to avoid stale fill
                    if (!(slice.ContainsKey(symbol) && slice[symbol] != None))
                    {
                        continue;
                    }
                    
                    if (_targetDirection == InsightDirection.Up && !algorithm.Portfolio[symbol].Invested)
                    {
                        insights.Add(Insight.Price(symbol, TimeSpan.FromDays(90), InsightDirection.Up));
                    }
                    else if (_targetDirection == InsightDirection.Flat && algorithm.Portfolio[symbol].Invested)
                    {
                        insights.Add(Insight.Price(symbol, _newsAffectDuration, InsightDirection.Flat));
                    }
                }
                return insights;
            }
    
            public override void OnSecuritiesChanged(QCAlgorithm algorithm, SecurityChanges changes)
            {
                foreach (var security in changes.AddedSecurities)
                {
                    _symbols.Add(security.Symbol);
                }
                
                foreach (var security in changes.RemovedSecurities)
                {
                    _symbols.Remove(security.Symbol);
                }
            }
        }
    }
}

Data Point Attributes

The US Regulatory Alerts dataset provides RegalyticsRegulatoryArticle and RegalyticsRegulatoryArticles objects.

RegalyticsRegulatoryArticle

RegalyticsRegulatoryArticle objects have the following attributes:

RegalyticsRegulatoryArticles

RegalyticsRegulatoryArticles objects have the following attributes:

You can also see our Videos. You can also get in touch with us via Discord.

Did you find this page helpful?

Contribute to the documentation: