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
Original file line number Diff line number Diff line change
Expand Up @@ -80,8 +80,10 @@ public override void Initialize()
// Initialize this flag, to check when the ema indicators crosses between themselves
_emaFastIsNotSet = true;

// Disable automatic exports as we manually set them
SignalExport.AutomaticExportTimeSpan = null;
// Set Collective2 signal export provider
SignalExport.AddSignalExportProviders(new Collective2SignalExport(_collective2ApiKey, _collective2SystemId));
SignalExport.AddSignalExportProvider(new Collective2SignalExport(_collective2ApiKey, _collective2SystemId));

SetWarmUp(100);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -95,12 +95,15 @@ public override void Initialize()
// Initialize this flag, to check when the ema indicators crosses between themselves
_emaFastIsNotSet = true;

// Disable automatic exports as we manually set them
SignalExport.AutomaticExportTimeSpan = null;

// Set Collective2 signal export provider.
// If using the Collective2 white-label API, you can specify it in the constructor with the optional parameter `useWhiteLabelApi`:
// e.g. new Collective2SignalExport(_collective2ApiKey, _collective2SystemId, useWhiteLabelApi: true)
// The API url can also be overridden by setting the Destination property:
// e.g. new Collective2SignalExport(_collective2ApiKey, _collective2SystemId) { Destination = new Uri("your url") }
SignalExport.AddSignalExportProviders(new Collective2SignalExport(_collective2ApiKey, _collective2SystemId));
SignalExport.AddSignalExportProvider(new Collective2SignalExport(_collective2ApiKey, _collective2SystemId));

SetWarmUp(100);
}
Expand Down
113 changes: 113 additions & 0 deletions Algorithm.CSharp/CustomSignalExportDemonstrationAlgorithm.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
/*
* 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 Newtonsoft.Json;
using QuantConnect.Algorithm.Framework.Portfolio;
using QuantConnect.Algorithm.Framework.Portfolio.SignalExports;
using QuantConnect.Api;
using QuantConnect.Data;
using QuantConnect.Interfaces;
using System;
using System.Linq;
using System.Net.Http;
using System.Net.Http.Json;
using System.Text;

namespace QuantConnect.Algorithm.CSharp
{
/// <summary>
/// This algorithm sends a list of portfolio targets to custom endpoint
/// </summary>
/// <meta name="tag" content="using data" />
/// <meta name="tag" content="using quantconnect" />
/// <meta name="tag" content="securities and portfolio" />
public class CustomSignalExportDemonstrationAlgorithm : QCAlgorithm
{
/// <summary>
/// Initialize the date and add all equity symbols present
/// </summary>
public override void Initialize()
{
SetStartDate(2013, 10, 07);
SetEndDate(2013, 10, 11);

/// Our custom signal export accepts all asset types
AddEquity("SPY", Resolution.Second);
AddCrypto("BTCUSD", Resolution.Second);
AddForex("EURUSD", Resolution.Second);
AddFutureContract(QuantConnect.Symbol.CreateFuture("ES", Market.CME, new DateTime(2023, 12, 15), null));
AddOptionContract(QuantConnect.Symbol.CreateOption("SPY", Market.USA, OptionStyle.American, OptionRight.Call, 130, new DateTime(2023, 9, 1)));

// Set CustomSignalExport signal export provider.
SignalExport.AddSignalExportProvider(new CustomSignalExport());
}

/// <summary>
/// Buy and hold EURUSD and SPY
/// </summary>
/// <param name="slice"></param>
public override void OnData(Slice slice)
{
foreach (var ticker in new[] { "SPY", "EURUSD", "BTCUSD" })
{
if (!Portfolio[ticker].Invested && Securities[ticker].HasData)
{
SetHoldings(ticker, 0.5m);
}
}
}
}

internal class CustomSignalExport : ISignalExportTarget
{
private readonly Uri _requestUri = new ("http://localhost:5000/");
private readonly HttpClient _httpClient = new();

public bool Send(SignalExportTargetParameters parameters)
{
object SimplePayload(PortfolioTarget target)
{
var newTarget = PortfolioTarget.Percent(parameters.Algorithm, target.Symbol, target.Quantity);
return new { symbol = newTarget.Symbol.Value, quantity = newTarget.Quantity };
};

var message = JsonConvert.SerializeObject(parameters.Targets.Select(SimplePayload));
using var httpMessage = new StringContent(message, Encoding.UTF8, "application/json");
using HttpResponseMessage response = _httpClient.PostAsync(_requestUri, httpMessage).Result;
var result = response.Content.ReadFromJsonAsync<RestResponse>().Result;
parameters.Algorithm.Log($"Send #{parameters.Targets.Count} targets. Success: {result.Success}");
return result.Success;
}

public void Dispose() => _httpClient.Dispose();
}
}

/*
# To test the algorithm, you can create a simple Python Flask application (app.py) and run flask
# $ flask --app app run

# app.py:
from flask import Flask, request, jsonify
from json import loads
app = Flask(__name__)
@app.post('/')
def handle_positions():
result = loads(request.data)
print(result)
return jsonify({'success': True,'message': f'{len(result)} positions received'})
if __name__ == '__main__':
app.run(debug=True)
*/
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ public override void Initialize()

_index = AddIndex("SPX").Symbol;
_equity = AddEquity("SPY").Symbol;
SignalExport.AutomaticExportTimeSpan = null;
_signalExportManagerTest = new SignalExportManagerTest(this);
Securities[_index].IsTradable = IsTradable;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,12 @@ public override void Initialize()
var numeraiModelId = "";

var numeraiFilename = ""; // (Optional) Replace this value with your submission filename
SignalExport.AddSignalExportProviders(new NumeraiSignalExport(numeraiPublicId, numeraiSecretId, numeraiModelId, numeraiFilename));

// Disable automatic exports as we manually set them
SignalExport.AutomaticExportTimeSpan = null;

// Set Numerai signal export provider
SignalExport.AddSignalExportProvider(new NumeraiSignalExport(numeraiPublicId, numeraiSecretId, numeraiModelId, numeraiFilename));
}

public void SubmitSignals()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,8 +63,10 @@ public override void Initialize()
_fast = EMA(underlying, 10, Resolution.Minute);
_slow = EMA(underlying, 50, Resolution.Minute);

// Disable automatic exports as we manually set them
SignalExport.AutomaticExportTimeSpan = null;
// Set up the Collective2 Signal Export with the provided API key and system ID
SignalExport.AddSignalExportProviders(new Collective2SignalExport(_collective2ApiKey, _collective2SystemId));
SignalExport.AddSignalExportProvider(new Collective2SignalExport(_collective2ApiKey, _collective2SystemId));

// Set warm-up period for the indicators
SetWarmUp(50);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,11 @@ def initialize(self):
# Collective2 System ID: This value is found beside the system's name (strategy's name) on the main system page
self.collective2_system_id = 0

self.signal_export.add_signal_export_providers(Collective2SignalExport(self.collective2_apikey, self.collective2_system_id))
# Disable automatic exports as we manually set them
self.signal_export.automatic_export_time_span = None

# Set Collective2 signal export provider
self.signal_export.add_signal_export_provider(Collective2SignalExport(self.collective2_apikey, self.collective2_system_id))

self.first_call = True

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,11 +61,14 @@ def initialize(self):
# Collective2 System ID: This value is found beside the system's name (strategy's name) on the main system page
self.collective2_system_id = 0

# Disable automatic exports as we manually set them
self.signal_export.automatic_export_time_span = None

# If using the Collective2 white-label API, you can specify it in the constructor with the optional parameter `use_white_label_api`:
# e.g. Collective2SignalExport(self.collective2_apikey, self.collective2_system_id, use_white_label_api=True)
# The API url can also be overridden by setting the Destination property:
# e.g. Collective2SignalExport(self.collective2_apikey, self.collective2_system_id) { Destination = new Uri("your url") }
self.signal_export.add_signal_export_providers(Collective2SignalExport(self.collective2_apikey, self.collective2_system_id))
self.signal_export.add_signal_export_provider(Collective2SignalExport(self.collective2_apikey, self.collective2_system_id))

self.first_call = True

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,15 +28,18 @@ def initialize(self):
self.set_end_date(2023, 5, 26)
self.set_cash(1_000_000)

# Disable automatic exports as we manually set them
self.signal_export.automatic_export_time_span = None

# Connect to CrunchDAO
api_key = "" # Your CrunchDAO API key
model = "" # The Id of your CrunchDAO model
submission_name = "" # A name for the submission to distinguish it from your other submissions
comment = "" # A comment for the submission
self.signal_export.add_signal_export_providers(CrunchDAOSignalExport(api_key, model, submission_name, comment))
self.signal_export.add_signal_export_provider(CrunchDAOSignalExport(api_key, model, submission_name, comment))

self.set_security_initializer(BrokerageModelSecurityInitializer(self.brokerage_model, FuncSecuritySeeder(self.get_last_known_prices)))

# Add a custom data universe to read the CrunchDAO skeleton
self.add_universe(CrunchDaoSkeleton, "CrunchDaoSkeleton", Resolution.DAILY, self.select_symbols)

Expand Down
77 changes: 77 additions & 0 deletions Algorithm.Python/CustomSignalExportDemonstrationAlgorithm.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
# 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>
### his algorithm sends a list of portfolio targets to custom endpoint
### </summary>
### <meta name="tag" content="using data" />
### <meta name="tag" content="using quantconnect" />
### <meta name="tag" content="securities and portfolio" />
class CustomSignalExportDemonstrationAlgorithm(QCAlgorithm):

def initialize(self) -> None:
''' Initialize the date and add all equity symbols present in list _symbols '''

self.set_start_date(2013, 10, 7) #Set Start Date
self.set_end_date(2013, 10, 11) #Set End Date
self.set_cash(100000) #Set Strategy Cash

# Our custom signal export accepts all asset types
self.add_equity("SPY", Resolution.SECOND)
self.add_crypto("BTCUSD", Resolution.SECOND)
self.add_forex("EURUSD", Resolution.SECOND)
self.add_future_contract(Symbol.create_future("ES", Market.CME, datetime(2023, 12, 15), None))
self.add_option_contract(Symbol.create_option("SPY", Market.USA, OptionStyle.American, OptionRight.Call, 130, datetime(2023, 9, 1)))

# Set CustomSignalExport signal export provider.
self.signal_export.add_signal_export_provider(CustomSignalExport())

def on_data(self, data: Slice) -> None:
'''Buy and hold EURUSD and SPY'''
for ticker in [ "SPY", "EURUSD", "BTCUSD" ]:
if not self.portfolio[ticker].invested and self.securities[ticker].has_data:
self.set_holdings(ticker, 0.5)

from requests import post
class CustomSignalExport:
def send(self, parameters: SignalExportTargetParameters) -> bool:
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 ]
response = post("http://localhost:5000/", json = data)
result = response.json()
success = result.get('success', False)
parameters.algorithm.log(f"Send #{len(parameters.targets)} targets. Success: {success}");
return success

def dispose(self):
pass

'''
# To test the algorithm, you can create a simple Python Flask application (app.py) and run flask
# $ flask --app app run

# app.py:
from flask import Flask, request, jsonify
from json import loads
app = Flask(__name__)
@app.post('/')
def handle_positions():
result = loads(request.data)
print(result)
return jsonify({'success': True,'message': f'{len(result)} positions received'})
if __name__ == '__main__':
app.run(debug=True)
'''
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,12 @@ def initialize(self):
numerai_model_id = ""

numerai_filename = "" # (Optional) Replace this value with your submission filename
self.signal_export.add_signal_export_providers(NumeraiSignalExport(numerai_public_id, numerai_secret_id, numerai_model_id, numerai_filename))

# Disable automatic exports as we manually set them
self.signal_export.automatic_export_time_span = None

# Set Numerai signal export provider
self.signal_export.add_signal_export_provider(NumeraiSignalExport(numerai_public_id, numerai_secret_id, numerai_model_id, numerai_filename))


def submit_signals(self):
Expand Down
7 changes: 7 additions & 0 deletions AlgorithmFactory/Python/Wrappers/AlgorithmPythonWrapper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
using QuantConnect.Data.Market;
using QuantConnect.Algorithm.Framework.Alphas.Analysis;
using QuantConnect.Commands;
using QuantConnect.Algorithm.Framework.Portfolio.SignalExports;

namespace QuantConnect.AlgorithmFactory.Python.Wrappers
{
Expand Down Expand Up @@ -564,6 +565,12 @@ public int ProjectId
/// </summary>
public StatisticsResults Statistics => _baseAlgorithm.Statistics;

/// <summary>
/// SignalExport - Allows sending export signals to different 3rd party API's. For example, it allows to send signals
/// to Collective2, CrunchDAO and Numerai API's
/// </summary>
public SignalExportManager SignalExport => ((QCAlgorithm)_baseAlgorithm).SignalExport;

/// <summary>
/// Set a required SecurityType-symbol and resolution for algorithm
/// </summary>
Expand Down
Loading