Пример #1
0
        public async Task <Data.Daily.Price> GetLastPrice(Data.Asset asset)
        {
            DateTime lastMarketClose = DateTime.UtcNow - new TimeSpan(1, 0, 0, 0);
            object   result          = await Alpaca.GetTime_LastMarketClose();

            if (result is DateTime dt)
            {
                lastMarketClose = dt;
            }
            else
            {
                Prompt.WriteLine("Unable to access market schedule/times via Alpaca API");
            }

            DateTime validity = await Database.GetValidity_Daily(asset);

            if (validity.CompareTo(lastMarketClose) < 0)
            {
                await Update_TSD(new List <Data.Asset>() { asset });

                await Task.Delay(2000);                 // Allow Database update thread to get ahead
            }

            Data.Daily dd = await Database.GetData_Daily(asset);

            return(dd.Prices.Last());
        }
Пример #2
0
        public async Task Update_TSD(List <Data.Asset> assets)
        {
            List <Task> threads = new List <Task>();

            DateTime lastMarketClose = DateTime.UtcNow - new TimeSpan(1, 0, 0, 0);
            object   result          = await Alpaca.GetTime_LastMarketClose();

            if (result is DateTime dt)
            {
                lastMarketClose = dt;
            }
            else
            {
                Prompt.WriteLine("Unable to access market schedule/times via Alpaca API");
            }

            int retryCounter = 0;

            await Settings.ClearCache();                // Routine emptying of cache directory

            // Iterate all symbols in list (assets), call API to download data, write to files in library
            for (int i = 0; i < assets.Count; i++)
            {
                Prompt.Write($"  [{i + 1:0000} / {assets.Count:0000}]  {assets[i].Symbol,-8}  ");

                /* Check validity timestamp against last known market close
                 */

                DateTime validity = await Database.GetValidity_Daily(assets[i]);

                if (validity.CompareTo(lastMarketClose) > 0)
                {
                    await Task.Delay(10);               // Allows GUI responsiveness

                    Prompt.WriteLine("Database current. Skipping.");
                    continue;
                }

                Prompt.Write("Requesting data. ");

                object     output = null;
                Data.Daily dd     = new Data.Daily();

                if (Settings.Library_DataProvider == Settings.Option_DataProvider.Alpaca)
                {
                    output = await Alpaca.GetData_Daily(assets[i], Settings.Library_LimitDailyEntries);
                }
                else if (Settings.Library_DataProvider == Settings.Option_DataProvider.AlphaVantage)
                {
                    string apiOutput   = "";
                    string apiFilePath = Path.Combine(Settings.GetCacheDirectory(), Path.GetRandomFileName());
                    string apiCache    = $"{apiFilePath}.cache";
                    string apiLockout  = $"{apiFilePath}.lockout";

                    DateTime timeoutTime = DateTime.Now + new TimeSpan(0, 1, 0);        // 1 minute timeout
                    _ = AlphaVantage.CacheData_Daily(assets[i].Symbol, apiCache, apiLockout);

                    while (!File.Exists(apiLockout) && DateTime.Now <= timeoutTime)
                    {
                        await Task.Delay(500);
                    }

                    if (File.Exists(apiLockout))
                    {
                        if (!File.Exists(apiCache))
                        {
                            apiOutput = "ERROR:TIMEOUT";
                        }
                        else
                        {
                            StreamReader sr = new StreamReader(apiCache);
                            apiOutput = await sr.ReadToEndAsync();

                            sr.Close();
                            sr.Dispose();
                        }

                        try {
                            if (File.Exists(apiCache))
                            {
                                File.Delete(apiCache);
                            }

                            if (File.Exists(apiLockout))
                            {
                                File.Delete(apiLockout);
                            }
                        } catch (Exception ex) {
                            await Log.Error($"{MethodBase.GetCurrentMethod().DeclaringType}: {MethodBase.GetCurrentMethod().Name}", ex);
                        }
                    }
                    else
                    {
                        apiOutput = "ERROR:TIMEOUT";
                    }

                    if (apiOutput == "ERROR:INVALID" ||
                        apiOutput == "ERROR:INVALIDKEY" ||
                        apiOutput == "ERROR:EXCEEDEDCALLS" ||
                        apiOutput == "ERROR:EXCEPTION" ||
                        apiOutput == "ERROR:TIMEOUT" ||
                        apiOutput.StartsWith("ERROR:WEBEXCEPTION:"))
                    {
                        output = apiOutput;
                    }
                    else
                    {
                        Prompt.Write("Parsing. ");
                        output = await AlphaVantage.ParseData_Daily(apiOutput, Settings.Library_LimitDailyEntries);
                    }
                }

                if (output is Data.Daily pmdd)
                {
                    dd           = pmdd;
                    retryCounter = 0;
                }
                else if (output is string pms)
                {
                    if (pms == "Too Many Requests" ||               // Alpaca's return message for exceeding API calls
                        pms == "ERROR:EXCEEDEDCALLS")               // Alpha Vantage's return message for exceeding API calls
                    {
                        Prompt.WriteLine("Exceeded API calls per minute- pausing for 30 seconds.");

                        await Task.Delay(30000);

                        i--;
                        retryCounter = 0;
                        continue;
                    }
                    else if (pms == "ERROR:EXCEPTION" || pms == "ERROR:TIMEOUT")
                    {
                        if (pms == "ERROR:EXCEPTION")
                        {
                            Prompt.WriteLine($"Error, Attempt #{retryCounter + 1}");
                        }
                        else if (pms == "ERROR:TIMEOUT")
                        {
                            Prompt.WriteLine($"Timeout, Attempt #{retryCounter + 1}");
                        }

                        if (retryCounter < 4)
                        {
                            i--;
                            retryCounter++;
                        }
                        else
                        {
                            retryCounter = 0;
                        }

                        continue;
                    }
                    else
                    {
                        Prompt.WriteLine($"Error: {output}");
                        retryCounter = 0;
                        continue;
                    }
                }
                else if (output == null)
                {
                    Prompt.WriteLine($"Error: See Error Log.");
                    retryCounter = 0;
                    continue;
                }

                dd.Asset = assets[i];

                /* Calculate metrics, stock indicators
                 */
                Prompt.Write("Calculating indicators. ");
                dd = await Calculate.Metrics(dd);

                /* Save to Database
                 * Use threading for highly improved speed!
                 */

                Prompt.WriteLine("Updating Database.", ConsoleColor.Green);

                Task thread = new Task(async() => { await Database.SetData_Daily(dd); });
                thread.Start();
                threads.Add(thread);

                int awaiting = threads.FindAll(t => t.Status == TaskStatus.Running).Count;
                if (awaiting >= 10)
                {
                    await Task.Delay(1000);
                }
            }

            int finishing = threads.FindAll(t => t.Status == TaskStatus.Running).Count;

            if (finishing > 0)
            {
                Prompt.WriteLine($"  Completing {finishing} remaining background Database tasks.");
                await Task.Delay(5000);

                finishing = threads.FindAll(t => t.Status == TaskStatus.Running).Count;
            }
        }
Пример #3
0
        // Calculates all the indicator metrics for a dataset
        public static async Task <Data.Daily> Metrics(Data.Daily dd)
        {
            // Prepare the data structures and tie Prices <-> Metrics

            dd.Prices.Sort((a, b) => a.Date.CompareTo(b.Date));
            foreach (Data.Daily.Price p in dd.Prices)
            {
                Data.Daily.Metric m = new Data.Daily.Metric()
                {
                    Price = p
                };
                p.Metric = m;
                dd.Metrics.Add(m);
            }

            // Run all calculations! Get all indicators!

            int amount = dd.Prices.Count;

            SmaResult[] sma7   = amount > 7 ? Indicator.GetSma(dd.Prices, 7).ToArray() : null;
            SmaResult[] sma20  = amount > 20 ? Indicator.GetSma(dd.Prices, 20).ToArray() : null;
            SmaResult[] sma50  = amount > 50 ? Indicator.GetSma(dd.Prices, 50).ToArray() : null;
            SmaResult[] sma100 = amount > 100 ? Indicator.GetSma(dd.Prices, 100).ToArray() : null;
            SmaResult[] sma200 = amount > 200 ? Indicator.GetSma(dd.Prices, 200).ToArray() : null;

            EmaResult[] ema7  = amount > 110 ? Indicator.GetEma(dd.Prices, 7).ToArray() : null;
            EmaResult[] ema20 = amount > 120 ? Indicator.GetEma(dd.Prices, 20).ToArray() : null;
            EmaResult[] ema50 = amount > 150 ? Indicator.GetEma(dd.Prices, 50).ToArray() : null;

            EmaResult[] dema7  = amount > 120 ? Indicator.GetDoubleEma(dd.Prices, 7).ToArray() : null;
            EmaResult[] dema20 = amount > 140 ? Indicator.GetDoubleEma(dd.Prices, 20).ToArray() : null;
            EmaResult[] dema50 = amount > 200 ? Indicator.GetDoubleEma(dd.Prices, 50).ToArray() : null;

            EmaResult[] tema7  = amount > 130 ? Indicator.GetTripleEma(dd.Prices, 7).ToArray() : null;
            EmaResult[] tema20 = amount > 160 ? Indicator.GetTripleEma(dd.Prices, 20).ToArray() : null;
            EmaResult[] tema50 = amount > 250 ? Indicator.GetTripleEma(dd.Prices, 50).ToArray() : null;

            RocResult[] roc7   = amount > 8 ? Indicator.GetRoc(dd.Prices, 7).ToArray() : null;
            RocResult[] roc14  = amount > 15 ? Indicator.GetRoc(dd.Prices, 14).ToArray() : null;
            RocResult[] roc50  = amount > 51 ? Indicator.GetRoc(dd.Prices, 50).ToArray() : null;
            RocResult[] roc100 = amount > 101 ? Indicator.GetRoc(dd.Prices, 100).ToArray() : null;
            RocResult[] roc200 = amount > 201 ? Indicator.GetRoc(dd.Prices, 200).ToArray() : null;

            RsiResult[]            rsi   = amount > 140 ? Indicator.GetRsi(dd.Prices).ToArray() : null;
            BollingerBandsResult[] bb    = amount > 20 ? Indicator.GetBollingerBands(dd.Prices).ToArray() : null;
            MacdResult[]           macd  = amount > 140 ? Indicator.GetMacd(dd.Prices).ToArray() : null;
            StochResult[]          stoch = amount > 20 ? Indicator.GetStoch(dd.Prices).ToArray() : null;
            ChopResult[]           chop  = amount > 15 ? Indicator.GetChop(dd.Prices).ToArray() : null;

            // Put indicator data back into data set for usability

            for (int i = 0; i < dd.Metrics.Count; i++)
            {
                try {
                    dd.Metrics[i].SMA7   = sma7?[i].Sma;
                    dd.Metrics[i].SMA20  = sma20?[i].Sma;
                    dd.Metrics[i].SMA50  = sma50?[i].Sma;
                    dd.Metrics[i].SMA100 = sma100?[i].Sma;
                    dd.Metrics[i].SMA200 = sma200?[i].Sma;

                    dd.Metrics[i].EMA7  = ema7?[i].Ema;
                    dd.Metrics[i].EMA20 = ema20?[i].Ema;
                    dd.Metrics[i].EMA50 = ema50?[i].Ema;

                    dd.Metrics[i].DEMA7  = dema7?[i].Ema;
                    dd.Metrics[i].DEMA20 = dema20?[i].Ema;
                    dd.Metrics[i].DEMA50 = dema50?[i].Ema;

                    dd.Metrics[i].TEMA7  = tema7?[i].Ema;
                    dd.Metrics[i].TEMA20 = tema20?[i].Ema;
                    dd.Metrics[i].TEMA50 = tema50?[i].Ema;

                    dd.Metrics[i].ROC7   = roc7?[i].Roc;
                    dd.Metrics[i].ROC14  = roc14?[i].Roc;
                    dd.Metrics[i].ROC50  = roc50?[i].Roc;
                    dd.Metrics[i].ROC100 = roc100?[i].Roc;
                    dd.Metrics[i].ROC200 = roc200?[i].Roc;

                    dd.Metrics[i].Choppiness = chop?[i].Chop;
                    dd.Metrics[i].RSI        = rsi?[i].Rsi;

                    dd.Metrics[i].BB         = bb?[i];
                    dd.Metrics[i].MACD       = macd?[i];
                    dd.Metrics[i].Stochastic = stoch?[i];
                } catch (Exception ex) {
                    Prompt.WriteLine($"Error casting indicators to dataset for {dd.Asset.Symbol}!", ConsoleColor.Red);
                    await Log.Error($"{MethodBase.GetCurrentMethod().DeclaringType}: {MethodBase.GetCurrentMethod().Name}", ex);
                }
            }

            return(dd);
        }