Beispiel #1
0
        public async Task UpdatePositions()
        {
            var positions = await SpotwareAccountApi.GetPositions(this).ConfigureAwait(false);

            this.positions.Clear();
            this.positions.AddRange(positions);
            Console.WriteLine(DumpPositions(Positions));
        }
Beispiel #2
0
        // ENH: max request size, and progress reporting
        protected override async Task Run()
        {
            try
            {
#if MaxRuns
                //if (runsremaining-- <= 0)
                //{
                //    UpdateProgress(1, "Canceled (test)");
                //    return;
                //}
#endif

                //MarketSeriesBase = MarketSeries ?? (MarketSeriesBase)MarketTickSeries;
                bool useTicks = TimeFrame.Name == "t1";
                if (useTicks)
                {
                    ResultTicks = new List <Tick>();
                }
                else
                {
                    ResultBars = new List <TimedBar>();
                }

                if (
                    MinItems == 0 &&
                    !StartTime.HasValue)
                {
                    UpdateProgress(1, "Done.  (No action since MinBars == 0 && !StartTime.HasValue)");
                    return;
                }
                UpdateProgress(0.1, "Starting");

                var apiInfo = Defaults.TryGet <ISpotwareConnectAppInfo>();

                var client = SpotwareAccountApi.NewHttpClient();

                #region Calculate req

                double multiplier;

                if (TimeFrame.TimeSpan.TotalHours % 1.0 == 0.0)
                {
                    requestTimeFrame = "h1";
                    multiplier       = TimeFrame.TimeSpan.TotalHours;
                }
                else if (TimeFrame.TimeFrameUnit == TimeFrameUnit.Tick)
                {
                    requestTimeFrame = "m1";
                    multiplier       = TimeFrame.TimeSpan.TotalMinutes / 2.0; // Estimation
                }
                else
                {
                    requestTimeFrame = "m1";
                    multiplier       = TimeFrame.TimeSpan.TotalMinutes;
                }

                int daysPageSize;

                int requestBars = (int)(MinItems * multiplier);

                //var prefix = "{ \"data\":[";

#if AllowRewind
                bool rewind = false;
                rewind = DateUtils.IsMarketDate(StartTime, EndTime);
                // TODO: Subtract days
                //int MarketOpenHour = 21; //
                //int MarketCloseHour = 22; //
                //switch (EndTime.DayOfWeek)
                //{
                //    case DayOfWeek.Friday:
                //        break;
                //    case DayOfWeek.Saturday:
                //        EndTime = EndTime - TimeSpan.FromDays(1);
                //        rewind = true;
                //        break;
                //    case DayOfWeek.Sunday:
                //        if (EndTime.Hour < MarketOpenHour)
                //        {
                //            EndTime = EndTime - TimeSpan.FromDays(2);
                //            rewind = true;
                //        }
                //        break;
                //    default:
                //        break;
                //}
                if (rewind)
                {
                    EndTime = new DateTime(EndTime.Year, EndTime.Month, EndTime.Day, MarketCloseHour, 0, 0);
                }
#endif

                EndTime = CropTheFuture(EndTime);
                if (StartTime.HasValue)
                {
                    startTime = StartTime.Value;
                    // TODO: maxBarsPerRequest?
                }
                else if (requestBars > 0)
                {
                    if (requestTimeFrame == "h1")
                    {
                        startTime = EndTime - TimeSpan.FromHours(requestBars);
                    }
                    else
                    {
                        startTime = EndTime - TimeSpan.FromMinutes(requestBars);
                    }
                }
                else
                {
                    throw new Exception("!StartTime.HasValue && requestBars <= 0");
                }

                startTime = CropTheFuture(startTime);

                if (requestTimeFrame == "h1")
                {
                    daysPageSize = Math.Max(1, maxBarsPerRequest / 24);
                }
                else
                {
                    daysPageSize = Math.Max(1, maxBarsPerRequest / (24 * 60));
                }

                #endregion

                var InitialEndTime  = EndTime;
                var endTimeIterator = EndTime;

                var timeSpan = endTimeIterator - startTime;
                if (timeSpan.TotalDays < 0)
                {
                    throw new ArgumentException("timespan is negative");
                }

                if (timeSpan.TotalDays > daysPageSize)
                {
                    Debug.WriteLine("WARNING TODO: download historical trendbars - timeSpan.TotalDays > daysPageSize.  TimeSpan: " + timeSpan);
                }

                var downloadedTickSets = new Stack <List <Tick> >();
                var downloadedBarSets  = new Stack <SpotwareTrendbar[]>();

                int totalItemsDownloaded = 0;
                int tryAgainCount        = 0;
tryagain:

                if (startTime == default(DateTime))
                {
                    throw new ArgumentException("startTime == default(DateTime)");
                }

                string from, to, date;

                if (useTicks)
                {
                    from = startTime.ToSpotwareTimeUriParameter();
                    to   = CropTheFuture(endTimeIterator).ToSpotwareTimeUriParameter();
                    date = startTime.Date.ToString("yyyyMMdd");

                    if (startTime.Date != EndTime.Date)
                    {
                        throw new NotSupportedException("startTime.Date != EndTime.Date for ticks");
                    }
                }
                else
                {
                    from = startTime.ToSpotwareUriParameter();
                    to   = CropTheFuture(endTimeIterator).ToSpotwareUriParameter();
                    date = "";
                    //bidOrAsk = "";
                }

                var uri = useTicks ? SpotwareAccountApi.TicksUri : SpotwareAccountApi.TrendBarsUri;
                uri = uri
                      .Replace("{symbolName}", Symbol)
                      .Replace("{requestTimeFrame}", requestTimeFrame)
                      .Replace("{id}", AccountId.ToString())
                      .Replace("{oauth_token}", System.Uri.EscapeDataString(AccessToken))
                      .Replace("{from}", from)
                      .Replace("{to}", to)
                      .Replace("{date}", date)
                ;

                // Read from stream: see http://stackoverflow.com/questions/26601594/what-is-the-correct-way-to-use-json-net-to-parse-stream-of-json-objects

                DateTime queryDate = DateTime.UtcNow;

                {
                    bool showedWaiting429 = false;
                    while (DateTime.UtcNow - lastQuery < TimeSpan.FromSeconds(WaitTime429InSeconds))
                    {
                        if (!showedWaiting429)
                        {
                            showedWaiting429 = true;
                            UpdateProgress(0.11, $"Waiting to avoid 429");
                        }
                        await Task.Delay(100);
                    }
                }
                lastQuery = DateTime.UtcNow;

                UpdateProgress(0.2, $"Sending request: {from}-{to}");

                int retryCount = 1;

                var response1 = await client.GetAsyncWithRetries(uri.Replace("{bidOrAsk}", "bid"), retryDelayMilliseconds : 10000,
                                                                 onFail : hrm =>
                {
                    UpdateProgress(0.21, $"Re-sending request (retry {retryCount++} after code {hrm.StatusCode})", LogLevel.Warning);
                    //lastQuery = DateTime.UtcNow;
                },
                                                                 canContinue : () => (DateTime.UtcNow - lastQuery) < TimeSpan.FromSeconds(WaitTime429InSeconds)
                                                                 , cancellationToken : this.CancellationToken).ConfigureAwait(false);

                lastQuery = DateTime.UtcNow;

                HttpResponseMessage response2 = null;

                if (useTicks)
                {
                    response2 = await client.GetAsyncWithRetries(uri.Replace("{bidOrAsk}", "ask"),
                                                                 retryDelayMilliseconds : 10000,
                                                                 onFail : hrm => UpdateProgress(0.21, $"Re-sending request (retry {retryCount++} after code {hrm.StatusCode})"),
                                                                 canContinue : () => DateTime.UtcNow - lastQuery < TimeSpan.FromSeconds(2.1), cancellationToken : this.CancellationToken
                                                                 )
                                .ConfigureAwait(false);

                    lastQuery = DateTime.UtcNow;
                }

                UpdateProgress(0.30, "Receiving response");
                string json = null;
                {
                    var receiveStream = await response1.Content.ReadAsStreamAsync().ConfigureAwait(false);

                    System.IO.StreamReader readStream = new System.IO.StreamReader(receiveStream, System.Text.Encoding.UTF8);
                    json = readStream.ReadToEnd();
                }

                string askJson = null;
                if (useTicks)
                {
                    var receiveStream = await response2.Content.ReadAsStreamAsync().ConfigureAwait(false);

                    System.IO.StreamReader readStream = new System.IO.StreamReader(receiveStream, System.Text.Encoding.UTF8);
                    askJson = readStream.ReadToEnd();
                }

                UpdateProgress(0.65, "Deserializing");
                var error = Newtonsoft.Json.JsonConvert.DeserializeObject <SpotwareErrorContainer>(json);
                if (error?.error != null)
                {
                    throw new Exception($"API returned error: {error.error.errorCode} - '{error.error.description}'");
                }
                if (String.IsNullOrWhiteSpace(json))
                {
                    throw new Exception($"API returned empty response.  StatusCode:  {response1.StatusCode}");
                }

                if (useTicks)
                {
                    var bidData = Newtonsoft.Json.JsonConvert.DeserializeObject <SpotwareTicksResult>(json);
                    var askData = Newtonsoft.Json.JsonConvert.DeserializeObject <SpotwareTicksResult>(askJson);

                    if (bidData.data == null)
                    {
                        throw new Exception($"API returned no bid data.  StatusCode:  {response1.StatusCode}");
                    }
                    if (askData.data == null)
                    {
                        throw new Exception($"API returned no ask data.  StatusCode:  {response2.StatusCode}");
                    }
                    if (bidData.data.Length >= 4999)
                    {
                        throw new Exception("probably didn't load all from Spotware.  Max: 5000.  TODO: repeat request, asking for next set of ticks.");
                    }
                    if (askData.data.Length >= 4999)
                    {
                        throw new Exception("probably didn't load all from Spotware.  Max: 5000.  TODO: repeat request, asking for next set of ticks.");
                    }

                    var ticks = AggregateTicks(bidData, askData);
                    downloadedTickSets.Push(ticks);
                    totalItemsDownloaded += ticks.Count;
                }
                else
                {
                    var data = Newtonsoft.Json.JsonConvert.DeserializeObject <SpotwareTrendbarsResult>(json);
                    if (data.data == null)
                    {
                        throw new Exception($"API returned no data.  StatusCode:  {response1.StatusCode}");
                    }

                    downloadedBarSets.Push(data.data);
                    totalItemsDownloaded += data.data.Length;
                }

                if (MinItems > 0 && totalItemsDownloaded < MinItems)
                {
                    //int lessThanExpectedAmount = MinItems - data2.Count; // OLD
                    int lessThanExpectedAmount = MinItems - totalItemsDownloaded;

                    if (tryAgainCount > MaxTryAgainCount)
                    {
                        throw new Exception($"Didn't get the requested {MinItems} minimum bars.  Tried rewinding to {endTimeIterator}.  If this rewind is not enough, increase MaxTryAgainCount.");
                    }
                    switch (requestTimeFrame)
                    {
                    case "t1":
                    {
                        var amount = TimeSpan.FromMinutes(Math.Min(TryAgainRewindHours * 60 * 60, lessThanExpectedAmount));
                        endTimeIterator = startTime - TimeSpan.FromMilliseconds(1);         // REVIEW: can two ticks happen at the same millisecond and would the data supplier only give me one?
                        startTime      -= amount;
                        break;
                    }

                    case "m1":
                    {
                        var amount = TimeSpan.FromMinutes(Math.Min(TryAgainRewindHours * 60, lessThanExpectedAmount));
                        endTimeIterator = startTime - TimeSpan.FromMinutes(1);
                        startTime      -= amount;
                        break;
                    }

                    case "h1":
                    {
                        var amount = TimeSpan.FromHours(Math.Min(TryAgainRewindHours, lessThanExpectedAmount));
                        endTimeIterator = startTime - TimeSpan.FromHours(1);
                        startTime      -= amount;
                        break;
                    }

                    default:
                        throw new NotImplementedException();
                    }
                    tryAgainCount++;
                    goto tryagain;
                }

                UpdateProgress(0.96, "Processing data");

                DateTime firstDownloaded = new DateTime(9999, 12, 31, 23, 59, 59, 999, DateTimeKind.Utc);
                DateTime lastDownloaded  = new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc);

                if (useTicks)
                {
                    var sets = downloadedTickSets;
                    while (sets.Count > 0)
                    {
                        var set = sets.Pop();

                        if (set.Count > 0)
                        {
                            Debug.WriteLine($"[data] {Symbol} {TimeFrame.Name} Loading {set.Count} bars {set[0].Time.ToString(DateFormat)} to {set[set.Count - 1].Time.ToString(DateFormat)}");

                            firstDownloaded = firstDownloaded.Min(set[0].Time);
                            lastDownloaded  = lastDownloaded.Max(set[set.Count - 1].Time);

                            ResultTicks.AddRange(set);
                        }
                    }
                }
                else
                {
                    var sets = downloadedBarSets;

                    while (sets.Count > 0)
                    {
                        var set = sets.Pop();

                        // TOSANITYCHECK: verify contiguous
                        if (set.Length > 0)
                        {
                            //Debug.WriteLine($"[{Symbol}-{TimeFrame.Name} Loading bars {set[0].timestamp.ToDateTime().ToString(DateFormat)} to {set[set.Length - 1].timestamp.ToDateTime().ToString(DateFormat)}");

                            firstDownloaded = firstDownloaded.Min(set[0].timestamp.ToDateTime());
                            lastDownloaded  = lastDownloaded.Max(set[set.Length - 1].timestamp.ToDateTime());

                            foreach (var b in set)
                            {
                                ResultBars.Add(new TimedBar()
                                {
                                    OpenTime = b.timestamp.ToDateTime(),
                                    Open     = b.open,
                                    High     = b.high,
                                    Low      = b.low,
                                    Close    = b.close,
                                    Volume   = b.volume,
                                });
                            }
                        }
                    }
                }

                var itemCountStr = ResultBars != null ? $"{ResultBars.Count} bars" : $"{ResultTicks?.Count} ticks";
                var dateStr      = firstDownloaded == DateTime.MaxValue ? "(no data)" : $"{firstDownloaded} to {lastDownloaded}";
                logger.LogInformation($"[{Symbol}-{TimeFrame.Name} - DOWNLOADED {itemCountStr}] {dateStr}");

                UpdateProgress(1, "Done");
                Faulted = false;
            }
            catch (Exception ex)
            {
                Faulted = true;
                UpdateProgress(double.NaN, "Exception: " + ex.ToString());
                throw;
            }
        }