16 using Newtonsoft.Json.Linq;
19 using System.Collections.Generic;
21 using System.Net.Http;
34 private readonly
string _apiKey;
39 private readonly Uri _destination;
44 private readonly
string _model;
49 private readonly
string _submissionName;
54 private readonly
string _comment;
64 private readonly HashSet<SecurityType> _allowedSecurityTypes =
new()
72 protected override string Name {
get; } =
"CrunchDAO";
91 _submissionName = submissionName;
93 _destination =
new Uri($
"https://api.tournament.crunchdao.com/v3/alpha-submissions?apiKey={apiKey}");
106 if (!base.Send(parameters))
116 if (!GetCurrentRoundID(out
int currentRoundId))
121 if (GetLastSubmissionId(currentRoundId, out
int lastSubmissionId))
123 _algorithm.
Debug($
"You have already submitted a signal for round {currentRoundId}. Your last submission is going to be overwritten with the new one");
124 if (!DeleteLastSubmission(lastSubmissionId))
130 var result = SendPositions(positions);
143 var holdings = parameters.
Targets;
145 positions =
"ticker,date,signal\n";
147 foreach (var holding
in holdings)
149 if (holding.Quantity < 0 || holding.Quantity > 1)
151 _algorithm.
Error($
"All signals must be between 0 and 1, but {holding.Symbol.Value} signal was {holding.Quantity}");
155 positions += $
"{_algorithm.Ticker(holding.Symbol)},{_algorithm.Securities[holding.Symbol].LocalTime.ToString("yyyy-MM-dd
")},{holding.Quantity.ToStringInvariant()}\n";
167 private bool SendPositions(
string positions)
170 var positionsStream =
new MemoryStream();
171 using var writer =
new StreamWriter(positionsStream);
172 writer.Write(positions);
174 positionsStream.Position = 0;
177 using var file =
new StreamContent(positionsStream);
178 using var model =
new StringContent(_model);
179 using var submissionName =
new StringContent(_submissionName);
180 using var comment =
new StringContent(_comment);
183 using var httpMessage =
new MultipartFormDataContent
186 { submissionName,
"label" },
187 { comment,
"comment" },
188 { file,
"file",
"submission.csv" }
192 using HttpResponseMessage response =
HttpClient.PostAsync(_destination, httpMessage).Result;
193 if (response.StatusCode == System.Net.HttpStatusCode.Locked || response.StatusCode == System.Net.HttpStatusCode.Forbidden)
195 var responseContent = response.Content.ReadAsStringAsync().Result;
196 var parsedResponseContent = JObject.Parse(responseContent);
197 _algorithm.
Error($
"CrunchDAO API returned code: {parsedResponseContent["code
"]} message:{parsedResponseContent["message
"]}");
201 if (!response.IsSuccessStatusCode)
203 _algorithm.
Error($
"CrunchDAO API returned HttpRequestException {response.StatusCode}");
216 private bool GetCurrentRoundID(out
int currentRoundId)
220 using HttpResponseMessage roundIdResponse =
HttpClient.GetAsync(
"https://api.tournament.crunchdao.com/v2/rounds/@current").Result;
221 if (roundIdResponse.StatusCode == System.Net.HttpStatusCode.NotFound)
223 var responseContent = roundIdResponse.Content.ReadAsStringAsync().Result;
224 var parsedResponseContent = JObject.Parse(responseContent);
225 _algorithm.
Error($
"CrunchDAO API returned code: {parsedResponseContent["code
"]} message:{parsedResponseContent["message
"]}");
228 else if (!roundIdResponse.IsSuccessStatusCode)
230 _algorithm.
Error($
"CrunchDAO API returned HttpRequestException {roundIdResponse.StatusCode}");
234 var roundIdResponseContent = roundIdResponse.Content.ReadAsStringAsync().Result;
235 currentRoundId = (int)(JObject.Parse(roundIdResponseContent)[
"id"]);
246 private bool GetLastSubmissionId(
int currentRoundId, out
int lastSubmissionId)
248 using HttpResponseMessage submissionIdResponse =
HttpClient.GetAsync($
"https://tournament.crunchdao.com/api/v3/alpha-submissions?includeAll=false&roundId={currentRoundId}&apiKey={_apiKey}").Result;
250 if (!submissionIdResponse.IsSuccessStatusCode)
252 _algorithm.
Error($
"CrunchDAO API returned the following Error Code: {submissionIdResponse.StatusCode}");
253 lastSubmissionId = -1;
257 var submissionIdResponseContent = submissionIdResponse.Content.ReadAsStringAsync().Result;
258 var parsedSubmissionIdResponseContent = JArray.Parse(submissionIdResponseContent);
259 if (!parsedSubmissionIdResponseContent.HasValues)
262 lastSubmissionId = -1;
266 lastSubmissionId = (int)parsedSubmissionIdResponseContent[0][
"id"];
275 private bool DeleteLastSubmission(
int lastSubmissionId)
277 using HttpResponseMessage deleteSubmissionResponse =
HttpClient.DeleteAsync($
"https://tournament.crunchdao.com/api/v3/alpha-submissions/{lastSubmissionId}?&apiKey={_apiKey}").Result;
278 if (!deleteSubmissionResponse.IsSuccessStatusCode)
280 var responseContent = deleteSubmissionResponse.Content.ReadAsStringAsync().Result;
281 var parsedResponseContent = JObject.Parse(responseContent);
282 _algorithm.
Error($
"CrunchDAO API returned code: {parsedResponseContent["code
"]} message:{parsedResponseContent["message
"]}. Last submission could not be deleted");
286 _algorithm.
Debug($
"Last submission has been deleted");