Skip to content

Commit cbf9fcb

Browse files
committed
Improves Custom Signal Example
Shows how to send signals with quantity instead of weight.
1 parent 2da8092 commit cbf9fcb

File tree

2 files changed

+22
-5
lines changed

2 files changed

+22
-5
lines changed

Algorithm.CSharp/CustomSignalExportDemonstrationAlgorithm.cs

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,13 @@
1414
*/
1515

1616
using Newtonsoft.Json;
17+
using QuantConnect.Algorithm.Framework.Portfolio;
1718
using QuantConnect.Algorithm.Framework.Portfolio.SignalExports;
1819
using QuantConnect.Api;
1920
using QuantConnect.Data;
2021
using QuantConnect.Interfaces;
2122
using System;
23+
using System.Linq;
2224
using System.Net.Http;
2325
using System.Net.Http.Json;
2426
using System.Text;
@@ -43,6 +45,7 @@ public override void Initialize()
4345

4446
/// Our custom signal export accepts all asset types
4547
AddEquity("SPY", Resolution.Second);
48+
AddCrypto("BTCUSD", Resolution.Second);
4649
AddForex("EURUSD", Resolution.Second);
4750
AddFutureContract(QuantConnect.Symbol.CreateFuture("ES", Market.CME, new DateTime(2023, 12, 15), null));
4851
AddOptionContract(QuantConnect.Symbol.CreateOption("SPY", Market.USA, OptionStyle.American, OptionRight.Call, 130, new DateTime(2023, 9, 1)));
@@ -57,7 +60,7 @@ public override void Initialize()
5760
/// <param name="slice"></param>
5861
public override void OnData(Slice slice)
5962
{
60-
foreach (var ticker in new[] { "SPY", "EURUSD" })
63+
foreach (var ticker in new[] { "SPY", "EURUSD", "BTCUSD" })
6164
{
6265
if (!Portfolio[ticker].Invested && Securities[ticker].HasData)
6366
{
@@ -74,10 +77,17 @@ internal class CustomSignalExport : ISignalExportTarget
7477

7578
public bool Send(SignalExportTargetParameters parameters)
7679
{
77-
var message = JsonConvert.SerializeObject(parameters.Targets);
80+
object SimplePayload(PortfolioTarget target)
81+
{
82+
var newTarget = PortfolioTarget.Percent(parameters.Algorithm, target.Symbol, target.Quantity);
83+
return new { symbol = newTarget.Symbol.Value, quantity = newTarget.Quantity };
84+
};
85+
86+
var message = JsonConvert.SerializeObject(parameters.Targets.Select(SimplePayload));
7887
using var httpMessage = new StringContent(message, Encoding.UTF8, "application/json");
7988
using HttpResponseMessage response = _httpClient.PostAsync(_requestUri, httpMessage).Result;
8089
var result = response.Content.ReadFromJsonAsync<RestResponse>().Result;
90+
parameters.Algorithm.Log($"Send #{parameters.Targets.Count} targets. Success: {result.Success}");
8191
return result.Success;
8292
}
8393

@@ -95,6 +105,7 @@ from json import loads
95105
@app.post('/')
96106
def handle_positions():
97107
result = loads(request.data)
108+
print(result)
98109
return jsonify({'success': True,'message': f'{len(result)} positions received'})
99110
if __name__ == '__main__':
100111
app.run(debug=True)

Algorithm.Python/CustomSignalExportDemonstrationAlgorithm.py

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ def initialize(self) -> None:
3030

3131
# Our custom signal export accepts all asset types
3232
self.add_equity("SPY", Resolution.SECOND)
33+
self.add_crypto("BTCUSD", Resolution.SECOND)
3334
self.add_forex("EURUSD", Resolution.SECOND)
3435
self.add_future_contract(Symbol.create_future("ES", Market.CME, datetime(2023, 12, 15), None))
3536
self.add_option_contract(Symbol.create_option("SPY", Market.USA, OptionStyle.American, OptionRight.Call, 130, datetime(2023, 9, 1)))
@@ -39,17 +40,21 @@ def initialize(self) -> None:
3940

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

4647
from requests import post
4748
class CustomSignalExport:
4849
def send(self, parameters: SignalExportTargetParameters) -> bool:
49-
data = { x.symbol.value: x.quantity for x in parameters.targets }
50+
targets = [PortfolioTarget.percent(parameters.algorithm, x.symbol, x.quantity)
51+
for x in parameters.targets] ;
52+
data = [ {'symbol' : x.symbol.value, 'quantity': x.quantity} for x in targets ]
5053
response = post("http://localhost:5000/", json = data)
5154
result = response.json()
52-
return result.get('success', False)
55+
success = result.get('success', False)
56+
parameters.algorithm.log(f"Send #{len(parameters.targets)} targets. Success: {success}");
57+
return success
5358

5459
def dispose(self):
5560
pass
@@ -64,6 +69,7 @@ def dispose(self):
6469
@app.post('/')
6570
def handle_positions():
6671
result = loads(request.data)
72+
print(result)
6773
return jsonify({'success': True,'message': f'{len(result)} positions received'})
6874
if __name__ == '__main__':
6975
app.run(debug=True)

0 commit comments

Comments
 (0)