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

Signal Exports

Key Concepts

Introduction

QuantConnect Signal Exports allows you to transmit the state of an algorithm's trading and portfolio positions to your fund or a third-party service. QuantConnect implements two signal services out of the box: Collective2 and Numerai. To send portfolio targets to your fund, you need to create a custom Signal Export implementation.

Add Providers

To export signals to a signal provider, during initialization, add a signal export provider.

Select Language:
self.signal_export.add_signal_export_provider(CustomSignalExport())

You can add multiple signal export providers to a single algorithm.

Send Portfolio Targets

The signal export manager automatically sends signals when your portfolio holdings change to your fund or a third-party service. By default, it waits five seconds after an order is filled to aggregate all the state changes into a single post. Set the automatic_export_time_span property to change the waiting time.

Select Language:
self.signal_export.automatic_export_time_span = timedelta(seconds=1)

To send targets that aren't based on your portfolio holdings, see Manual Exports.

To disable automatic exports, set the automatic_export_time_span property to None.

Select Language:
self.signal_export.automatic_export_time_span = None

Provider Structure

Signal export providers must implement the ISignalExportTarget interface. Extensions of the ISignalExportTarget interface must define the send and the dispose methods.

The send receives a SignalExportTargetParameters object with a list of PortfolioTarget objects you can use to create the API request payload.

The dispose method is called when the algorithm is disposed. You can use this method to release unmanaged resources such as HTTP Clients.

Select Language:
class CustomSignalExportExampleAlgorithm(QCAlgorithm):
    def initialize(self) -> None:
        # In the Initialize method, set the custom signal export provider
        self.add_equity("SPY")
        self.signal_export.add_signal_export_providers(CustomSignalExport())

    def on_data(self, slice: Slice) -> None:
        # Buy the SPY ETF when the algorithm is not invested
        if not self.portfolio.invested:
            self.set_holdings("SPY", 0.1)

# Define the custom signal export provider
from requests import post
class CustomSignalExport:
    def send(self, parameters: SignalExportTargetParameters) -> bool:
        # Create the request payload using the PortfolioTarget objects in the parameters
        # You can use the PortfolioTarget.Percent to calculate the target quantity 
        # from the target percentage
        targets = [PortfolioTarget.percent(parameters.algorithm, x.symbol, x.quantity) 
           for x in parameters.targets] ;
        data = [ {'symbol' : x.symbol.value, 'quantity': x.quantity} for x in targets ]

        # Send the request to your custom endpoint
        request_uri = "https://your-custom-endpoint.com/api/signal-export"
        response = post(request_uri, json = data)
        result = response.json()

        # Log the result of the request for debugging purposes
        success = result.get('success', False)
        parameters.algorithm.log(f"Send #{len(parameters.targets)} targets. Success: {success}");
        return success       

    def dispose(self) -> None:
        pass

Manual Exports

In some cases, you may need to send signals to your fund or a third-party manually. For example, the signal export manager sends signals after a fill event and you need to submit signals when the market is closed or your signals aren't based on your portfolio holdings.

To do this, pass a PortfolioTarget object or a list of PortfolioTarget objects to the set_target_portfolio method. The method returns a boolean that represents if the targets were successfully sent to its destination. In this situation, the number you pass to the PortfolioTarget constructor represents the portfolio weight. Don't use the PortfolioTarget.percent method.

Select Language:
target = PortfolioTarget(self._symbol, weight)
success = self.signal_export.set_target_portfolio(target)

If you use a margin account, you can send your current portfolio holdings by calling the set_target_portfolio_from_portfolio method.

Select Language:
success = self.signal_export.set_target_portfolio_from_portfolio()

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: