public static double GetPrice(string name, int quality, int craftable) //make sure it's full name!, also, no unusuals. mebe later. { BackpackAPI instance = (BackpackAPI)MemoryCache.Default.Get("BackpackTF"); double value; string currency; if (craftable == 0) { if (name.Contains("Crate")) { int crate; string[] words = name.Split('#'); crate = int.Parse(words[1]); value = instance.response.items[words[0]].prices[quality].tradable.uncraftable[crate].value; currency = instance.response.items[words[0]].prices[quality].tradable.uncraftable[crate].currency; } else { value = instance.response.items[name].prices[quality].tradable.uncraftable[0].value; currency = instance.response.items[name].prices[quality].tradable.uncraftable[0].currency; } } else { if (name.Contains("Crate")) { int crate; string[] words = name.Split('#'); crate = int.Parse(words[1]); value = instance.response.items[words[0]].prices[quality].tradable.craftable[crate].value; currency = instance.response.items[words[0]].prices[quality].tradable.craftable[crate].currency; } else { value = instance.response.items[name].prices[quality].tradable.craftable[0].value; currency = instance.response.items[name].prices[quality].tradable.craftable[0].currency; } } double price = StringParsing.StringToDouble(value + " " + currency, true); return(price); }
public double?FetchPrice(int z) { var absoluteExpirationPolicy = new CacheItemPolicy { AbsoluteExpiration = DateTime.Now.AddHours(2) }; List <double> PriceList = new List <double>(); List <string> ItemNames = new List <string>(); int p = 1; bool done = false; try { HtmlWeb htmlWeb = new HtmlWeb(); do { string url = "http://backpack.tf/classifieds?item=" + this.name + "&quality=" + this.quality + "&tradable=1&craftable=" + this.craftable + "&numeric=" + this.numeric + "&comparison=eq&value=" + this.crate + "&australium=" + this.australium + "&page=" + p; HtmlDocument htmlDocument = htmlWeb.Load(url); #region MUST BE UPDATED IEnumerable <HtmlNode> links; if (!cosmetic) { links = htmlDocument.DocumentNode.Descendants("li") .Where(x => x.Attributes.Contains("data-listing-price")) .Where(x => !x.Attributes.Contains("data-gifted-id")) .Where(x => x.Attributes["data-listing-intent"].Value == "1")//added this in because program was picking up buy orders ! scary... .Where(x => x.Attributes.Contains("data-listing-steamid")); //.Where(x => !x.Attributes["title"].Value.Contains("Killstreak")); } else { links = htmlDocument.DocumentNode.Descendants("li") .Where(x => x.Attributes.Contains("data-listing-price")) .Where(x => !x.Attributes.Contains("data-gifted-id")) .Where(x => x.Attributes["data-listing-intent"].Value == "1") .Where(x => x.Attributes.Contains("data-listing-steamid")) .Where(x => !x.Attributes.Contains("data-paint-name")) .Where(x => !x.Attributes["title"].Value.Contains("#")); } #endregion //this just gets every listing (will be used later; I call them "unfiltered listings") IEnumerable <HtmlNode> ulinks = htmlDocument.DocumentNode.Descendants("li") .Where(x => x.Attributes.Contains("data-listing-price")) .Where(x => x.Attributes.Contains("data-listing-steamid")); string[] uprices = ulinks.Select(x => x.Attributes["data-listing-price"].Value).ToArray(); if (uprices.Count() == 0) { this.price = null; return(null); } List <string> prices = links.Select(x => x.Attributes["data-listing-price"].Value).ToList(); ItemNames = links.Select(x => x.Attributes["title"].Value).ToList(); foreach (string element in prices) //this attempts to catch derp que-cutting listings. { double dub = StringParsing.StringToDouble(element, false); if (dub <= .25 * this.BPprice) { continue; } PriceList.Add(dub); } if (PriceList.Count >= z) { done = true; } else { p++; } } while (!done); while (PriceList.Count > z) { PriceList.RemoveAt(PriceList.Count - 1); } while (ItemNames.Count > z) { ItemNames.RemoveAt(ItemNames.Count - 1); } if (ItemNames.Contains(this.completename)) //I added this because I figured, if the killstreaks and the regular items are closely enough priced, I should be able to use these prices. I want to make it 2 names. { double Average = PriceList.Average(); double SumSquares = PriceList.Sum(d => Math.Pow(d - Average, 2)); double stddev = Math.Sqrt(SumSquares / (z - 1)); if (stddev < 5.742 * Math.Log(Average) - 10.525) //stddev <= 2.5 * Math.Log(.5 * Average)) //calculated from stats: 5.742ln(x) - 10.525 ... will it work? { if (Average >= 1.5 * double.Parse(MemoryCache.Default.Get("Mann Co. Supply Crate Key BP").ToString()) || this.name.Contains("Mann Co. Supply Crate Key")) // && Average<=BackpackAPI.GetPrice(name, quality, craftable)) use this if you want bp.tf to be the upper limit on calculated prices. I've not thoroughly tested out getprice, though { //Console.WriteLine(this.completename+" | "+Average+" | "+this.BPprice); Method.cachelock.EnterWriteLock(); #region Moving Average /* This will make the cache store a moving list instead of a fixed value; allows use of moving averages. I've since decided the mavg is not in the bot's benefit, but may be useful later on * List<double> maverage = new List<double>(); * if (!MemoryCache.Default.Contains(name + " " + quality.ToString() + " " + craftable.ToString())) * { * maverage.Add(Average); * } * else * { * maverage = (List<double>)MemoryCache.Default.Get(name + " " + quality.ToString() + " " + craftable.ToString()); * maverage.Add(Average); * } * * while (maverage.Count>3) * { * maverage.RemoveAt(0); * } * * MemoryCache.Default.Set(name + " " + quality.ToString() + " " + craftable.ToString(), maverage,absoluteExpirationPolicy); */ #endregion MemoryCache.Default.Set(this.completename, Average, absoluteExpirationPolicy); Method.cachelock.ExitWriteLock(); this.price = Average; using (StreamWriter sw = new StreamWriter("Prices.txt", true)) { sw.WriteLine(this.completename + " | " + this.price + " ref"); } return(Average); } else { this.price = null; return(null); } } else { this.price = null; return(null); } } else { this.price = null; return(null); } } catch (Exception ex) { Console.WriteLine("Uh Oh: Error " + ex); Console.ReadLine(); this.price = null; return(null); } }
public static void CacheItemPrice(string name, int z, int craftable, int quality, int cosmetic, bool omit) { var absoluteExpirationPolicy = new CacheItemPolicy { AbsoluteExpiration = DateTime.Now.AddMinutes(30) }; //this is a policy that forces cache entries to expire after 30 min // var watch = Stopwatch.StartNew(); List <double> PriceList = new List <double>(); List <string> ItemNames = new List <string>(); int p = 1; // this will be used as the page number for the url; starts at 1, increments if required bool done = false; //used for the do-while loop //enter try clause. if the code in the clause triggers any exception, the program moves immediately to the "catch" clause (which is further down) try { //Console.WriteLine(name); //for debugging purposes HtmlWeb htmlWeb = new HtmlWeb(); do { string url; if (name.Contains("#")) { string[] words = name.Split('#'); int crate = int.Parse(words[1]); url = "http://backpack.tf/classifieds?item=" + words[0].Trim() + "&quality=" + quality + "&tradable=1&craftable=" + craftable + "&numeric=crate&comparison=eq&value=" + crate + "&page=" + p; } else if (name.Contains("Australium")) { string newname = name.Replace("Australium", "").Trim(); url = "http://backpack.tf/classifieds?item=" + newname + "&quality=" + quality + "&tradable=1&craftable=" + craftable + "&australium=1" + "&page=" + p; } else { url = "http://backpack.tf/classifieds?item=" + name + "&quality=" + quality + "&tradable=1&craftable=" + craftable + "&page=" + p; } //Console.WriteLine(url); HtmlDocument htmlDocument = htmlWeb.Load(url); // Getting all links tagged 'li' and containing 'data-listing-price' (which is where the classified price is,found this through page source of the url above) //then, filter our gifted items, painted items. make sure there is a steamid so the bot can contact the guy if it must //NOTE: BP.tf automatically orders listings lowest to highest. the parser reads top down, so when I create the node list, the nodes with the cheap prices will be before the nodes with the expensive prices IEnumerable <HtmlNode> links; if (cosmetic == 0) { links = htmlDocument.DocumentNode.Descendants("li") .Where(x => x.Attributes.Contains("data-listing-price")) .Where(x => !x.Attributes.Contains("data-gifted-id")) .Where(x => x.Attributes.Contains("data-listing-steamid")); //.Where(x => !x.Attributes["title"].Value.Contains("Killstreak")); } else { links = htmlDocument.DocumentNode.Descendants("li") .Where(x => x.Attributes.Contains("data-listing-price")) .Where(x => !x.Attributes.Contains("data-gifted-id")) .Where(x => x.Attributes.Contains("data-listing-steamid")) .Where(x => !x.Attributes.Contains("data-paint-name")) .Where(x => !x.Attributes["title"].Value.Contains("#")); } //this just gets every listing (will be used later; I call them "unfiltered listings") IEnumerable <HtmlNode> ulinks = htmlDocument.DocumentNode.Descendants("li") .Where(x => x.Attributes.Contains("data-listing-price")) .Where(x => x.Attributes.Contains("data-listing-steamid")); //Now, Dumping list of prices to a string array string[] uprices = ulinks.Select(x => x.Attributes["data-listing-price"].Value).ToArray(); //if the page we're on has no listings at all (aka no unfiltered listings), break, cause there are no more listings to inspect if (uprices.Count() == 0) { //File.AppendAllText("Page_Overload.txt", name + Environment.NewLine); //Page_Overload is just a debugging file return; } List <string> prices = links.Select(x => x.Attributes["data-listing-price"].Value).ToList(); ItemNames = links.Select(x => x.Attributes["title"].Value).ToList(); //take each string in the string array separately foreach (string element in prices) { PriceList.Add(StringParsing.StringToDouble(element, false)); } if (omit) //stop when we have more than the number of listings we need (note, we stop at z+1 because the "omit" option in this method allows us to skip the first lowest listing (to combat trolls) { if (PriceList.Count >= z + 1) { done = true; } else { p++; } } else { if (PriceList.Count >= z) { done = true; } else { p++; } } } while (!done); if (omit) { while (PriceList.Count > z + 1) { PriceList.RemoveAt(PriceList.Count - 1); } PriceList.RemoveAt(0); //remove lowest listing while (ItemNames.Count > z + 1) { ItemNames.RemoveAt(ItemNames.Count - 1); } ItemNames.RemoveAt(0); //remove lowest listing } else { while (PriceList.Count > z) { PriceList.RemoveAt(PriceList.Count - 1); } while (ItemNames.Count > z) { ItemNames.RemoveAt(ItemNames.Count - 1); } } string name_1; if (quality == 1) { name_1 = "Genuine " + name; } else if (quality == 11) { name_1 = "Strange " + name; } else if (quality == 3) { name_1 = "Vintage " + name; } else { name_1 = name; } if (craftable == 0) { name_1 = "Non-Craftable " + name_1; } //Console.WriteLine(finalname); // going to average the list now, so we can get an average price for the item (this is how the bot determines the price of an item) if (ItemNames.Contains(name_1)) { double Average = PriceList.Average(); double SumSquares = PriceList.Sum(d => Math.Pow(d - Average, 2)); double stddev = Math.Sqrt(SumSquares / (z - 1)); if (stddev <= 2.5 * Math.Log(.5 * Average)) { //string price = name + " : " + Average; // File.AppendAllText("Prices.txt", price + Environment.NewLine); //implement the above line if you want a file with the price for each item the bot goes through if (Average >= 1.5 * double.Parse(MemoryCache.Default.Get("Mann Co.Supply Crate Key").ToString()) || name.Contains("Mann Co. Supply Crate Key")) // && Average<=BackpackAPI.GetPrice(name, quality, craftable)) use this if you want bp.tf to be the upper limit on calculated prices. I've not thoroughly tested out getprice, though { Method.cachelock.EnterWriteLock(); /* This will make the cache store a moving list instead of a fixed value; allows use of moving averages. I've since decided the mavg is not in the bot's benefit, but may be useful later on * List<double> maverage = new List<double>(); * if (!MemoryCache.Default.Contains(name + " " + quality.ToString() + " " + craftable.ToString())) * { * maverage.Add(Average); * } * else * { * maverage = (List<double>)MemoryCache.Default.Get(name + " " + quality.ToString() + " " + craftable.ToString()); * maverage.Add(Average); * } * * while (maverage.Count>3) * { * maverage.RemoveAt(0); * } * * MemoryCache.Default.Set(name + " " + quality.ToString() + " " + craftable.ToString(), maverage,absoluteExpirationPolicy); */ MemoryCache.Default.Set(name + " " + quality.ToString() + " " + craftable.ToString(), Average, absoluteExpirationPolicy); Method.cachelock.ExitWriteLock(); if (true) //deprecated { using (StreamWriter sw = new StreamWriter("Itemlist.txt", true)) { sw.Write(name + Environment.NewLine + quality + Environment.NewLine + cosmetic + Environment.NewLine); } // File.AppendAllText("ItemList.txt", name + Environment.NewLine + quality + Environment.NewLine + cosmetic + Environment.NewLine); } } //Console.WriteLine("All Done!"); //this is completely necessary } } } catch (Exception ex) { //in case we can't load the page Console.WriteLine("Uh Oh: Error " + ex); Console.ReadLine(); return; } //measure elapsed time // watch.Stop(); //var elapsedMs = watch.ElapsedMilliseconds; //Console.WriteLine("elapsed time: " + elapsedMs + "ms"); }
public double GetPrice(Tradebot.ItemInfo item, bool Average) //make sure it's full name!, also, no unusuals. mebe later. { var absoluteExpirationPolicy = new CacheItemPolicy { AbsoluteExpiration = DateTime.Now.AddHours(2) }; double value; double highvalue; string currency; try { if (item.craftable == 1) { value = this.response.items[item.fullname].prices[item.quality].tradable.craftable[item.crate].value; currency = this.response.items[item.fullname].prices[item.quality].tradable.craftable[item.crate].currency; highvalue = this.response.items[item.fullname].prices[item.quality].tradable.craftable[item.crate].value_high; } else { value = this.response.items[item.fullname].prices[item.quality].tradable.uncraftable[item.crate].value; currency = this.response.items[item.fullname].prices[item.quality].tradable.uncraftable[item.crate].currency; highvalue = this.response.items[item.fullname].prices[item.quality].tradable.uncraftable[item.crate].value_high; } double dub; if (Average) { if (highvalue != 0) { dub = StringParsing.StringToDouble((value + highvalue) / 2 + " " + currency, true); item.BPprice = dub; //Method.cachelock.EnterWriteLock(); MemoryCache.Default.Set(item.completename + " BP", item.BPprice, absoluteExpirationPolicy); //Method.cachelock.ExitWriteLock(); return(dub); } } dub = StringParsing.StringToDouble(value + " " + currency, true); item.BPprice = dub; Method.cachelock.EnterWriteLock(); MemoryCache.Default.Set(item.completename + " BP", item.BPprice, absoluteExpirationPolicy); Method.cachelock.ExitWriteLock(); return(dub); } catch (Exception ex) { Console.WriteLine("BP Api error" + " " + ex); using (StreamWriter sw = new StreamWriter("CorruptNames.txt", true)) { sw.WriteLine(item.fullname.ToString()); } item.BPprice = 0; return(0); } }
public Classifieds GetClassifieds() { try //try clause. the code will break from the try clause and move to the catch clause if there's a problem executing the code { string page; using (var myWebClient = new WebClient()) { myWebClient.Encoding = Encoding.UTF8; page = myWebClient.DownloadString("http://backpack.tf/classifieds/?tradable=1&quality=11,6,1,3&intent=1&sort=bump"); } //HtmlWeb Htmlweb = new HtmlWeb(); HtmlDocument htmlDocument = new HtmlDocument(); htmlDocument.LoadHtml(page); IEnumerable <HtmlNode> links = htmlDocument.DocumentNode.Descendants("li") //this is a tag that I observed preceded all the html nodes that contain price listings .Where(x => x.Attributes.Contains("data-listing-price")) //this is an attribute that an html node containing a price listing should have .Where(x => x.Attributes["data-listing-intent"].Value == "1") //sell orders! .Where(x => !x.Attributes.Contains("data-gifted-id")); //no gifted items foreach (HtmlNode element in links) { ClassifiedInfo info = new ClassifiedInfo(); string name = element.Attributes["data-name"].Value; //item name if (element.Attributes["data-slot"].Value.Contains("misc")) { info.cosmetic = true; } else { info.cosmetic = false; } if (name.Contains("#")) //not crate I believe { string[] words = name.Split('#'); info.crate = int.Parse(words[1].Trim()); info.numeric = "crate"; name = words[0].Trim(); } else { info.crate = 0; info.numeric = "0"; } if (name.Contains("Australium")) { info.australium = 1; name = name.Replace("Australium", ""); name = name.Trim(); } else { info.australium = 0; } info.name = name; info.quality = int.Parse(element.Attributes["data-quality"].Value); info.craftable = int.Parse(element.Attributes["data-craftable"].Value); info.listprice = StringParsing.StringToDouble(element.Attributes["data-listing-price"].Value, true); //item price, in string format, "x ref, y keys, z, buds"; it's just how the website formats it info.steamid = element.Attributes["data-listing-steamid"].Value; //the lister's steamid number string tradelink = ""; //the lister's trade offer link (not always provided) info.itemid = element.Attributes["data-id"].Value; info.GetNames(); if (MemoryCache.Default.Contains(info.completename)) { info.price = double.Parse(MemoryCache.Default.Get(info.completename).ToString()); } else { continue; } info.BPprice = double.Parse(MemoryCache.Default.Get(info.completename + " BP").ToString()); if (element.Attributes.Contains("data-listing-offers-url")) { tradelink = element.Attributes["data-listing-offers-url"].Value; tradelink = tradelink.Replace("token=", "^"); string[] words = tradelink.Split('^'); info.token = words.Last(); } bool flag = false; foreach (ClassifiedInfo thingy in this.ClassifiedItems) { if (thingy.itemid == info.itemid) { flag = true; break; } else { flag = false; } } if (!flag) { this.ClassifiedItems.Add(info); } } return(this); } catch (Exception ex) { Console.WriteLine("Classifieds Error" + ex); Console.Read(); return(null); } }