public Dictionary<int, decimal> GetPricesByRegion(IEnumerable<int> typeIDs, int regionID, PriceStat stat)
        {
            Dictionary<int, decimal> result;

            // do the query
            result = GetPriceHelper(typeIDs, regionID, stat);

            // save the cache sooner rather than later, just in case!
            SaveCache();

            // return it
            return result;
        }
        private Dictionary<int, decimal> GetPriceHelper(IEnumerable<int> typeIDs, int regionID, PriceStat stat)
        {
            Dictionary<int, MarketStat> parsed;
            Dictionary<int, MarketStat> cached = new Dictionary<int, MarketStat>();
            Dictionary<int, decimal> answer;
            List<int> uncachedTypeIDs = new List<int>();
            List<KeyValuePair<string, string>> parameters;
            string resultPath = null;

            // check the cache, add cache misses to the query parameters
            foreach (int typeID in typeIDs)
            {
                MarketStat value;

                if (TryGetCachedMarketStat(typeID, regionID, out value))
                    cached[typeID] = value;
                else
                    uncachedTypeIDs.Add(typeID);
            }

            try
            {
                // EVE Central allows us only 100 types per request
                for (int i = 0; i * MAX_TYPES_PER_QUERY < uncachedTypeIDs.Count; ++i)
                {
                    // progress feedback
                    OnUpdateProgress(i * MAX_TYPES_PER_QUERY, uncachedTypeIDs.Count);

                    // rate limit queries
                    lock (m_rateLock)
                    {
                        TimeSpan elapsed = DateTime.Now.Subtract(m_lastQuery);

                        if (elapsed < m_rateLimit)
                            System.Threading.Thread.Sleep(m_rateLimit.Subtract(elapsed));

                        m_lastQuery = DateTime.Now;
                    }

                    // generate typeid parameters for this iteration
                    parameters = new List<KeyValuePair<string, string>>();
                    for (int j = i * MAX_TYPES_PER_QUERY; j < uncachedTypeIDs.Count && j < (i + 1) * MAX_TYPES_PER_QUERY; ++j)
                        parameters.Add(new KeyValuePair<string, string>("typeid", uncachedTypeIDs[j].ToString()));

                    // if regionID has a value, fill in our single region limit
                    if (regionID > 0)
                        parameters.Add(new KeyValuePair<string, string>("regionlimit", regionID.ToString()));

                    try
                    {
                        // fetch the data we want
                        resultPath = Resources.DownloadUrlPost(EVECENTRAL_MARKETSTAT_URL, parameters);

                        // parse it
                        parsed = ParseMarketStat(resultPath);
                    }
                    finally
                    {
                        // clean up temp file
                        if (resultPath != null)
                        {
                            try { File.Delete(resultPath); }
                            catch { /* pass */ }
                        }
                    }

                    // cache the new stuff and copy to the cached dictionary for output below
                    foreach (KeyValuePair<int, MarketStat> entry in parsed)
                    {
                        CacheMarketStat(entry.Key, regionID, entry.Value);
                        cached[entry.Key] = entry.Value;
                    }
                }

                // progress update the last
                OnUpdateProgress(uncachedTypeIDs.Count, uncachedTypeIDs.Count);

                // convert output to the form we want
                answer = new Dictionary<int, decimal>(cached.Count);
                foreach (KeyValuePair<int, MarketStat> entry in cached)
                {
                    decimal price;

                    // read the requested value from the struct
                    switch (stat)
                    {
                        case PriceStat.Mean:
                            price = entry.Value.All.Avg;
                            break;
                        case PriceStat.Median:
                            price = entry.Value.All.Median;
                            break;
                        case PriceStat.High:
                            price = entry.Value.All.Max;
                            break;
                        case PriceStat.Low:
                            price = entry.Value.All.Min;
                            break;
                        default:
                            throw new ArgumentException("Don't know how to process PriceStat " + stat);
                    }

                    // add the converted value
                    answer[entry.Key] = price;
                }

                // return the answer
                return answer;
            }
            catch (Exception ex)
            {
                throw new PriceProviderException(PriceProviderFailureReason.UnexpectedError, "Unexpected error while querying EVE-Central prices", ex);
            }
        }
 public Dictionary<int, decimal> GetPrices(IEnumerable<int> typeIDs, PriceStat stat)
 {
     return GetPricesByRegion(typeIDs, PriceRegion.ALL, stat);
 }
 public Dictionary<int, decimal> GetPricesHighSec(IEnumerable<int> typeIDs, PriceStat stat)
 {
     throw new NotImplementedException();
 }
 public decimal GetPriceHighSec(int typeID, PriceStat stat)
 {
     throw new NotImplementedException();
 }
        public decimal GetPriceByRegion(int typeID, int regionID, PriceStat stat)
        {
            Dictionary<int, decimal> answer = GetPriceHelper(new int[] { typeID }, regionID, stat);
            decimal price;

            if (answer.TryGetValue(typeID, out price))
                return price;
            else
                throw new PriceProviderException(PriceProviderFailureReason.PriceMissing, "Answer did not contain the requested price");
        }
Exemple #7
0
        public void UpdatePrice(PriceEntryBase priceEntryBase)
        {
            DateTime now   = DateTime.Now;
            decimal  price = priceEntryBase.NetEarn;

            decimal totalPrice = price;
            int     totalCount = PriceList.Count;

            List <decimal> window = new List <decimal> {
                price
            };
            decimal windowedPrice = price;
            int     windowedCount = 0;
            bool    outlier       = false;

            if (!PriceList.ContainsKey(priceEntryBase))
            {
                PriceList.Add(priceEntryBase, new List <PriceStat>());
            }

            foreach (PriceStat stat in PriceList[priceEntryBase])
            {
                decimal historicPrice = stat.CurrentPrice;
                totalPrice += historicPrice;

                if (stat.Time == now)
                {
                    return;
                }
                if (stat.Time >= now - _statWindow)
                {
                    window.Add(historicPrice);
                    windowedPrice += historicPrice;
                    windowedCount++;
                }
            }

            decimal totalAveragePrice    = totalPrice / (totalCount + 1);
            decimal windowedAveragePrice = windowedPrice / (windowedCount + 1);

            if (windowedCount >= 10) // Makes sure at least ten entries are in there
            {
                window.Sort();
                if (_iqrMultiplier > 0)
                {
                    int     iqrIndex = (int)Math.Truncate(window.Count * 0.75);
                    decimal iqr      = window[iqrIndex] - window[window.Count - iqrIndex];
                    outlier = price > windowedAveragePrice + (_iqrMultiplier * iqr);
                }
                else
                {
                    // If the IQR multiplier is negative or zero,
                    // it'll try to use percentiles for outlierdetection
                    // Not advised! Will kill off trending profits, iqr-multiplying is preferable
                    int       outlierIndex = (int)Math.Truncate(window.Count * _percentile);
                    decimal[] outliers     = { window[outlierIndex], window[window.Count - outlierIndex] };
                    outlier = price > outliers.Max();
                }
            }


            PriceStat priceStat = new PriceStat
            {
                Time                 = now,
                CurrentPrice         = price,
                TotalAveragePrice    = totalAveragePrice,
                WindowedAveragePrice = windowedAveragePrice,
                Outlier              = outlier
            };

            priceEntryBase.Outlier    = outlier;
            priceEntryBase.NetAverage = windowedAveragePrice;

            PriceList[priceEntryBase].Add(priceStat);
        }
 public decimal GetPrice(int typeID, PriceStat stat)
 {
     return GetPriceByRegion(typeID, PriceRegion.ALL, stat);
 }
Exemple #9
0
 public decimal GetPriceByRegion(int typeID, int regionID, PriceStat stat)
 {
     return GetPriceInternal(typeID, regionID, stat);
 }
Exemple #10
0
 public Dictionary<int, decimal> GetPricesByRegion(IEnumerable<int> typeIDs, int regionID, PriceStat stat)
 {
     return GetPricesInternal(typeIDs, regionID, stat);
 }
Exemple #11
0
 public decimal GetPriceHighSec(int typeID, PriceStat stat)
 {
     return GetPriceByRegion(typeID, PriceRegion.CHS, stat);
 }
Exemple #12
0
        private Dictionary<int, decimal> GetPricesInternal(IEnumerable<int> typeIDs, int regionID, PriceStat stat)
        {
            Dictionary<int, ZofuEntry> regionCache;
            Dictionary<int, decimal> result = new Dictionary<int, decimal>();
            ZofuEntry entry;
            CacheResult cacheResult;

            // check and download the file if it's missing or out of date
            cacheResult = DownloadRegionFile(regionID);

            // all right, result, let's fill it
            lock (m_cache)
            {
                // see if we have prices for the region
                if (!m_cache.TryGetValue(regionID, out regionCache))
                    throw new PriceProviderException(PriceProviderFailureReason.CacheEmpty, "No prices available for region " + regionID.ToString(), cacheResult.Exception);

                // the easy part
                foreach (int typeID in typeIDs)
                {
                    if (regionCache.TryGetValue(typeID, out entry))
                    {
                        switch (stat)
                        {
                            case PriceStat.Mean:
                                result[typeID] = entry.Avg;
                                break;
                            case PriceStat.Median:
                                result[typeID] = entry.Median;
                                break;
                            case PriceStat.Low:
                                result[typeID] = entry.Low;
                                break;
                            case PriceStat.High:
                                result[typeID] = entry.High;
                                break;
                            default:
                                throw new ApplicationException("Unknown stat " + stat.ToString());
                        }
                    }
                }
            }

            // finally
            return result;
        }
Exemple #13
0
        private decimal GetPriceInternal(int typeID, int regionID, PriceStat stat)
        {
            Dictionary<int, decimal> result;
            decimal value;

            result = GetPricesInternal(new int[] { typeID }, regionID, stat);
            if (!result.TryGetValue(typeID, out value))
                throw new PriceProviderException(PriceProviderFailureReason.PriceMissing, "No price for typeID " + typeID.ToString());
            else
                return value;
        }
Exemple #14
0
        public void UpdatePrice(PriceEntryBase priceEntryBase)
        {
            DateTime now   = DateTime.Now;
            decimal  price = priceEntryBase.NetEarn;

            decimal totalPrice = price;
            int     totalCount = PriceList.Count;

            List <decimal> window = new List <decimal> {
                price
            };
            decimal windowedPrice = price;
            int     windowedCount = 0;
            bool    outlier       = false;

            if (!PriceList.ContainsKey(priceEntryBase))
            {
                PriceList.Add(priceEntryBase, new List <PriceStat>());
            }

            foreach (PriceStat stat in PriceList[priceEntryBase])
            {
                if (stat.CurrentPrice > 0)
                {
                    decimal historicPrice = stat.CurrentPrice;
                    totalPrice += historicPrice;

                    if (stat.Time == now)
                    {
                        return;
                    }
                    if (stat.Time >= now - _statWindow)
                    {
                        window.Add(historicPrice);
                        windowedPrice += historicPrice;
                        windowedCount++;
                    }
                }
            }

            decimal totalAveragePrice    = totalPrice / (totalCount + 1);
            decimal windowedAveragePrice = windowedPrice / (windowedCount + 1);

            if (windowedCount >= 10) // Makes sure at least ten entries are in there
            {
                window.Sort();
                if (_iqrMultiplier > 0)
                {
                    double sumOfSquareOfDifferences =
                        (double)PriceList[priceEntryBase].Where(stat => stat.Time >= now - _statWindow)
                        .Sum(stat =>
                             (stat.CurrentPrice - windowedAveragePrice) *
                             (stat.CurrentPrice - windowedAveragePrice));
                    decimal standardDeviation = (decimal)Math.Sqrt(sumOfSquareOfDifferences / windowedCount);
                    decimal top    = windowedAveragePrice + standardDeviation;
                    decimal bottom = windowedAveragePrice - standardDeviation;
                    decimal iqr    = top - bottom;
                    decimal max    = windowedAveragePrice + (iqr * _iqrMultiplier);
                    outlier = price > max;
                }
                else
                {
                    // If the IQR multiplier is negative or zero,
                    // it'll try to use percentiles for outlierdetection
                    // Not advised! Will kill off trending profits, iqr-multiplying is preferable
                    int       outlierIndex = (int)Math.Truncate(window.Count * _percentile);
                    decimal[] outliers     = { window[outlierIndex], window[window.Count - outlierIndex] };
                    outlier = price > outliers.Max();
                }
            }


            PriceStat priceStat = new PriceStat
            {
                Time                 = now,
                CurrentPrice         = price,
                TotalAveragePrice    = totalAveragePrice,
                WindowedAveragePrice = windowedAveragePrice,
                Outlier              = outlier
            };

            priceEntryBase.Outlier    = outlier;
            priceEntryBase.NetAverage = windowedAveragePrice;

            // if (priceEntryBase.Enabled == true)
            PriceList[priceEntryBase].Add(priceStat);
        }
        public void UpdatePrice(PriceEntryBase priceEntryBase)
        {
            DateTime now = DateTime.Now;
            decimal price = priceEntryBase.NetEarn;

            decimal totalPrice = price;
            int totalCount = PriceList.Count;

            List<decimal> window = new List<decimal> {price};
            decimal windowedPrice = price;
            int windowedCount = 0;
            bool outlier = false;

            if (!PriceList.ContainsKey(priceEntryBase))
                PriceList.Add(priceEntryBase, new List<PriceStat>());

            foreach (PriceStat stat in PriceList[priceEntryBase])
            {
                decimal historicPrice = stat.CurrentPrice;
                totalPrice += historicPrice;

                if (stat.Time == now) return;
                if (stat.Time >= now - _statWindow)
                {
                    window.Add(historicPrice);
                    windowedPrice += historicPrice;
                    windowedCount++;
                }
            }

            decimal totalAveragePrice = totalPrice/(totalCount+1);
            decimal windowedAveragePrice = windowedPrice/(windowedCount+1);

            if (windowedCount >= 10) // Makes sure at least ten entries are in there
            {
                window.Sort();
                if (_iqrMultiplier > 0)
                {
                    double sumOfSquareOfDifferences =
                        (double) PriceList[priceEntryBase].Where(stat => stat.Time >= now - _statWindow)
                            .Sum(stat =>
                                (stat.CurrentPrice - windowedAveragePrice) *
                                (stat.CurrentPrice - windowedAveragePrice));
                    decimal standardDeviation = (decimal) Math.Sqrt(sumOfSquareOfDifferences/windowedCount);
                    decimal top = windowedAveragePrice + standardDeviation;
                    decimal bottom = windowedAveragePrice - standardDeviation;
                    decimal iqr = top - bottom;
                    decimal max = windowedAveragePrice + (iqr * _iqrMultiplier);
                    outlier = price > max;
                }
                else
                {
                    // If the IQR multiplier is negative or zero,
                    // it'll try to use percentiles for outlierdetection
                    // Not advised! Will kill off trending profits, iqr-multiplying is preferable
                    int outlierIndex = (int) Math.Truncate(window.Count*_percentile);
                    decimal[] outliers = {window[outlierIndex], window[window.Count - outlierIndex]};
                    outlier = price > outliers.Max();
                }
            }

            PriceStat priceStat = new PriceStat
            {
                Time = now,
                CurrentPrice = price,
                TotalAveragePrice = totalAveragePrice,
                WindowedAveragePrice = windowedAveragePrice,
                Outlier = outlier
            };

            priceEntryBase.Outlier = outlier;
            priceEntryBase.NetAverage = windowedAveragePrice;

            PriceList[priceEntryBase].Add(priceStat);
        }