/* * 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 System; using RestSharp; using Newtonsoft.Json; using QuantConnect.Orders; using QuantConnect.Logging; using System.Threading.Tasks; using RestSharp.Authenticators; namespace QuantConnect.Api { /// /// API Connection and Hash Manager /// public class ApiConnection { private readonly static JsonSerializerSettings _jsonSettings = new() { Converters = { new LiveAlgorithmResultsJsonConverter(), new OrderJsonConverter() } }; /// /// Authorized client to use for requests. /// public RestClient Client { get; set; } // Authorization Credentials private readonly string _userId; private readonly string _token; private LeanAuthenticator _authenticator; /// /// Create a new Api Connection Class. /// /// User Id number from QuantConnect.com account. Found at www.quantconnect.com/account /// Access token for the QuantConnect account. Found at www.quantconnect.com/account public ApiConnection(int userId, string token) { _token = token; _userId = userId.ToStringInvariant(); Client = new RestClient(Globals.Api); } /// /// Return true if connected successfully. /// public bool Connected { get { var request = new RestRequest("authenticate", Method.GET); AuthenticationResponse response; if (TryRequest(request, out response)) { return response.Success; } return false; } } /// /// Place a secure request and get back an object of type T. /// /// /// /// Result object from the /// T typed object response public bool TryRequest(RestRequest request, out T result) where T : RestResponse { var resultTuple = TryRequestAsync(request).SynchronouslyAwaitTaskResult(); result = resultTuple.Item2; return resultTuple.Item1; } /// /// Place a secure request and get back an object of type T. /// /// /// /// T typed object response public async Task> TryRequestAsync(RestRequest request) where T : RestResponse { var responseContent = string.Empty; T result; try { SetAuthenticator(request); // Execute the authenticated REST API Call var restsharpResponse = await Client.ExecuteAsync(request).ConfigureAwait(false); //Verify success if (restsharpResponse.ErrorException != null) { Log.Error($"ApiConnection.TryRequest({request.Resource}): Error: {restsharpResponse.ErrorException.Message}"); return new Tuple(false, null); } if (!restsharpResponse.IsSuccessful) { Log.Error($"ApiConnect.TryRequest({request.Resource}): Content: {restsharpResponse.Content}"); } responseContent = restsharpResponse.Content; result = JsonConvert.DeserializeObject(responseContent, _jsonSettings); if (result == null || !result.Success) { Log.Debug($"ApiConnection.TryRequest({request.Resource}): Raw response: '{responseContent}'"); return new Tuple(false, result); } } catch (Exception err) { Log.Error($"ApiConnection.TryRequest({request.Resource}): Error: {err.Message}, Response content: {responseContent}"); return new Tuple(false, null); } return new Tuple(true, result); } private void SetAuthenticator(RestRequest request) { var newTimeStamp = (int)Time.TimeStamp(); var currentAuth = _authenticator; if (currentAuth == null || newTimeStamp - currentAuth.TimeStamp > 7000) { // Generate the hash each request // Add the UTC timestamp to the request header. // Timestamps older than 7200 seconds will not work. var hash = Api.CreateSecureHash(newTimeStamp, _token); var authenticator = new HttpBasicAuthenticator(_userId, hash); _authenticator = currentAuth = new LeanAuthenticator(authenticator, newTimeStamp); Client.Authenticator = currentAuth.Authenticator; } request.AddHeader("Timestamp", currentAuth.TimeStampStr); } private class LeanAuthenticator { public int TimeStamp { get; } public string TimeStampStr { get; } public HttpBasicAuthenticator Authenticator { get; } public LeanAuthenticator(HttpBasicAuthenticator authenticator, int timeStamp) { TimeStamp = timeStamp; Authenticator = authenticator; TimeStampStr = timeStamp.ToStringInvariant(); } } } }