16 using Newtonsoft.Json;
17 using Newtonsoft.Json.Linq;
20 using System.Collections.Generic;
22 using System.Net.Http;
39 private readonly Uri _destination;
44 private readonly
string _publicId;
49 private readonly
string _secretId;
54 private readonly
string _modelId;
59 private readonly
string _fileName;
69 private readonly Dictionary<string, string> _numeraiMarketFormat =
new()
78 private readonly HashSet<SecurityType> _allowedSecurityTypes =
new()
86 protected override string Name {
get; } =
"Numerai";
100 public NumeraiSignalExport(
string publicId,
string secretId,
string modelId,
string fileName =
"predictions.csv")
102 _destination =
new Uri(
"https://api-tournament.numer.ai");
103 _publicId = publicId;
104 _secretId = secretId;
106 _fileName = fileName;
117 if (!base.Send(parameters))
124 if (parameters.
Targets.Count < 10)
126 _algorithm.
Error($
"Numerai Signals API accepts minimum 10 different signals, just found {parameters.Targets.Count}");
134 var result = SendPositions(positions);
147 positions =
"numerai_ticker,signal\n";
148 foreach ( var holding
in parameters.Targets)
150 if (holding.Quantity <= 0 || holding.Quantity >= 1)
152 _algorithm.
Error($
"All signals must be between 0 and 1 (exclusive), but {holding.Symbol.Value} signal was {holding.Quantity}");
156 positions += $
"{parameters.Algorithm.Ticker(holding.Symbol)} {_numeraiMarketFormat[holding.Symbol.ID.Market]},{holding.Quantity.ToStringInvariant()}\n";
168 private bool SendPositions(
string positions)
171 var authQuery =
@"query($filename: String!
173 submissionUploadSignalsAuth(filename: $filename
182 filename = _fileName,
185 var argumentsMessage = JsonConvert.SerializeObject(arguments);
187 using var variables =
new StringContent(argumentsMessage, Encoding.UTF8,
"application/json");
188 using var query =
new StringContent(authQuery, Encoding.UTF8,
"application/json");
190 var httpMessage =
new MultipartFormDataContent
193 { variables,
"variables" }
196 using var authRequest =
new HttpRequestMessage(HttpMethod.Post, _destination);
197 authRequest.Headers.Add(
"Accept",
"application/json");
198 authRequest.Headers.Add(
"Authorization", $
"Token {_publicId}${_secretId}");
199 authRequest.Content = httpMessage;
200 var response =
HttpClient.SendAsync(authRequest).Result;
201 var responseContent = response.Content.ReadAsStringAsync().Result;
202 if (!response.IsSuccessStatusCode)
204 _algorithm.
Error($
"Numerai API returned HttpRequestException {response.StatusCode}");
208 var parsedResponseContent = JObject.Parse(responseContent);
209 if (!parsedResponseContent[
"data"][
"submissionUploadSignalsAuth"].HasValues)
211 _algorithm.
Error($
"Numerai API returned the following errors: {string.Join(",
", parsedResponseContent["errors
"])}");
215 var putUrl =
new Uri((
string)parsedResponseContent[
"data"][
"submissionUploadSignalsAuth"][
"url"]);
216 var submissionFileName = (string)parsedResponseContent[
"data"][
"submissionUploadSignalsAuth"][
"filename"];
220 var positionsStream =
new MemoryStream();
221 using var writer =
new StreamWriter(positionsStream);
222 writer.Write(positions);
224 positionsStream.Position = 0;
225 using var putRequest =
new HttpRequestMessage(HttpMethod.Put, putUrl)
227 Content =
new StreamContent(positionsStream)
229 var putResponse =
HttpClient.SendAsync(putRequest).Result;
232 var createQuery =
@"mutation($filename: String!
234 $triggerId: String) {
235 createSignalsSubmission(filename: $filename
237 triggerId: $triggerId
238 source: ""numerapi"") {
244 var createArguments =
new
246 filename = submissionFileName,
249 var createArgumentsMessage = JsonConvert.SerializeObject(createArguments);
251 using var submissionQuery =
new StringContent(createQuery, Encoding.UTF8,
"application/json");
252 using var submissionVariables =
new StringContent(createArgumentsMessage, Encoding.UTF8,
"application/json");
254 var submissionMessage =
new MultipartFormDataContent
256 {submissionQuery,
"query"},
257 {submissionVariables,
"variables"}
260 using var submissionRequest =
new HttpRequestMessage(HttpMethod.Post, _destination);
261 submissionRequest.Headers.Add(
"Authorization", $
"Token {_publicId}${_secretId}");
262 submissionRequest.Content = submissionMessage;
263 var submissionResponse =
HttpClient.SendAsync(submissionRequest).Result;
264 var submissionResponseContent = submissionResponse.Content.ReadAsStringAsync().Result;
265 if (!submissionResponse.IsSuccessStatusCode)
267 _algorithm.
Error($
"Numerai API returned HttpRequestException {submissionResponseContent}");
271 var parsedSubmissionResponseContent = JObject.Parse(submissionResponseContent);
272 if (!parsedSubmissionResponseContent[
"data"][
"createSignalsSubmission"].HasValues)
274 _algorithm.
Error($
"Numerai API returned the following errors: {string.Join(",
", parsedSubmissionResponseContent["errors
"])}");