private void OnFrame(object sender, EventArgs e) { if (State == ValueDumpState.Idle) { return; } var marketWindow = DirectEve.Windows.OfType <DirectMarketWindow>().FirstOrDefault(); var hangar = DirectEve.GetItemHangar(); var sellWindow = DirectEve.Windows.OfType <DirectMarketActionWindow>().FirstOrDefault(w => w.IsSellAction); var reprorcessingWindow = DirectEve.Windows.OfType <DirectReprocessingWindow>().FirstOrDefault(); switch (State) { case ValueDumpState.CheckMineralPrices: _currentMineral = InvTypesById.Values.FirstOrDefault(i => i.Id != 27029 && i.GroupId == 18 && i.LastUpdate < DateTime.Now.AddHours(-4)); if (_currentMineral == null) { if (DateTime.Now.Subtract(_lastExecute).TotalSeconds > 5) { State = ValueDumpState.SaveMineralPrices; if (marketWindow != null) { marketWindow.Close(); } } } else { State = ValueDumpState.GetMineralPrice; } break; case ValueDumpState.GetMineralPrice: if (marketWindow == null) { if (DateTime.Now.Subtract(_lastExecute).TotalSeconds > 5) { DirectEve.ExecuteCommand(DirectCmd.OpenMarket); _lastExecute = DateTime.Now; } return; } if (marketWindow.DetailTypeId != _currentMineral.Id) { if (DateTime.Now.Subtract(_lastExecute).TotalSeconds < 5) { return; } Log("Loading orders for " + _currentMineral.Name); marketWindow.LoadTypeId(_currentMineral.Id); _lastExecute = DateTime.Now; return; } if (!marketWindow.BuyOrders.Any(o => o.StationId == DirectEve.Session.StationId)) { _currentMineral.LastUpdate = DateTime.Now; Log("No orders found for " + _currentMineral.Name); State = ValueDumpState.CheckMineralPrices; } // Take top 5 orders, average the buy price and consider that median-buy (it's not really median buy but its what we want) _currentMineral.MedianBuy = marketWindow.BuyOrders.Where(o => o.StationId == DirectEve.Session.StationId).OrderByDescending(o => o.Price).Take(5).Average(o => o.Price); _currentMineral.LastUpdate = DateTime.Now; State = ValueDumpState.CheckMineralPrices; Log("Average price for " + _currentMineral.Name + " is " + _currentMineral.MedianBuy.Value.ToString("#,##0.00")); break; case ValueDumpState.SaveMineralPrices: Log("Saving InvItems.xml"); var xdoc = new XDocument(new XElement("invtypes")); foreach (var type in InvTypesById.Values.OrderBy(i => i.Id)) { xdoc.Root.Add(type.Save()); } xdoc.Save(InvTypesPath); State = ValueDumpState.Idle; break; case ValueDumpState.GetItems: if (hangar.Window == null) { // No, command it to open if (DateTime.Now.Subtract(_lastExecute).TotalSeconds > 5) { Log("Opening hangar"); DirectEve.ExecuteCommand(DirectCmd.OpenHangarFloor); _lastExecute = DateTime.Now; } return; } if (!hangar.IsReady) { return; } Log("Loading hangar items"); // Clear out the old Items.Clear(); var hangarItems = hangar.Items; if (hangarItems != null) { Items.AddRange(hangarItems.Where(i => i.ItemId > 0 && i.MarketGroupId > 0 && i.Quantity > 0).Select(i => new ItemCache(i, RefineCheckBox.Checked))); } State = ValueDumpState.UpdatePrices; break; case ValueDumpState.UpdatePrices: foreach (var item in Items) { InvType invType; if (!InvTypesById.TryGetValue(item.TypeId, out invType)) { Log("Unknown TypeId " + item.TypeId + " for " + item.Name); continue; } item.InvType = invType; foreach (var material in item.RefineOutput) { if (!InvTypesById.TryGetValue(material.TypeId, out invType)) { Log("Unknown TypeId " + material.TypeId + " for " + material.Name); continue; } material.InvType = invType; } } State = ValueDumpState.Idle; if (cbxSell.Checked) { // Copy the items to sell list ItemsToSell.Clear(); ItemsToRefine.Clear(); if (cbxUndersell.Checked) { ItemsToSell.AddRange(Items.Where(i => i.InvType != null)); } else { ItemsToSell.AddRange(Items.Where(i => i.InvType != null && i.InvType.MedianBuy.HasValue)); } State = ValueDumpState.NextItem; } break; case ValueDumpState.NextItem: if (ItemsToSell.Count == 0) { if (ItemsToRefine.Count != 0) { State = ValueDumpState.RefineItems; } else { State = ValueDumpState.Idle; } break; } Log(ItemsToSell.Count + " items left to sell"); _currentItem = ItemsToSell[0]; ItemsToSell.RemoveAt(0); // Dont sell containers if (_currentItem.GroupId == 448) { Log("Skipping " + _currentItem.Name); break; } State = ValueDumpState.StartQuickSell; break; case ValueDumpState.StartQuickSell: if (DateTime.Now.Subtract(_lastExecute).TotalSeconds < 1) { break; } _lastExecute = DateTime.Now; var directItem = hangar.Items.FirstOrDefault(i => i.ItemId == _currentItem.Id); if (directItem == null) { Log("Item " + _currentItem.Name + " no longer exists in the hanger"); break; } // Update Quantity _currentItem.QuantitySold = _currentItem.Quantity - directItem.Quantity; Log("Starting QuickSell for " + _currentItem.Name); if (!directItem.QuickSell()) { _lastExecute = DateTime.Now.AddSeconds(-5); Log("QuickSell failed for " + _currentItem.Name + ", retrying in 5 seconds"); break; } State = ValueDumpState.WaitForSellWindow; break; case ValueDumpState.WaitForSellWindow: if (sellWindow == null || !sellWindow.IsReady || sellWindow.Item.ItemId != _currentItem.Id) { break; } // Mark as new execution _lastExecute = DateTime.Now; Log("Inspecting sell order for " + _currentItem.Name); State = ValueDumpState.InspectOrder; break; case ValueDumpState.InspectOrder: // Let the order window stay open for 2 seconds if (DateTime.Now.Subtract(_lastExecute).TotalSeconds < 2) { break; } if (!sellWindow.OrderId.HasValue || !sellWindow.Price.HasValue || !sellWindow.RemainingVolume.HasValue) { Log("No order available for " + _currentItem.Name); sellWindow.Cancel(); State = ValueDumpState.WaitingToFinishQuickSell; break; } var price = sellWindow.Price.Value; var quantity = (int)Math.Min(_currentItem.Quantity - _currentItem.QuantitySold, sellWindow.RemainingVolume.Value); var totalPrice = quantity * price; string otherPrices = " "; if (_currentItem.InvType.MedianBuy.HasValue) { otherPrices += "[Median buy price: " + (_currentItem.InvType.MedianBuy.Value * quantity).ToString("#,##0.00") + "]"; } else { otherPrices += "[No median buy price]"; } if (RefineCheckBox.Checked) { var portions = quantity / _currentItem.PortionSize; var refinePrice = _currentItem.RefineOutput.Any() ? _currentItem.RefineOutput.Sum(m => m.Quantity * m.InvType.MedianBuy ?? 0) * portions : 0; refinePrice *= (double)RefineEfficiencyInput.Value / 100; otherPrices += "[Refine price: " + refinePrice.ToString("#,##0.00") + "]"; if (refinePrice > totalPrice) { Log("Refining gives a better price for item " + _currentItem.Name + " [Refine price: " + refinePrice.ToString("#,##0.00") + "][Sell price: " + totalPrice.ToString("#,##0.00") + "]"); // Add it to the refine list ItemsToRefine.Add(_currentItem); sellWindow.Cancel(); State = ValueDumpState.WaitingToFinishQuickSell; break; } } if (!cbxUndersell.Checked) { if (!_currentItem.InvType.MedianBuy.HasValue) { Log("No historical price available for " + _currentItem.Name); sellWindow.Cancel(); State = ValueDumpState.WaitingToFinishQuickSell; break; } var perc = price / _currentItem.InvType.MedianBuy.Value; var total = _currentItem.InvType.MedianBuy.Value * _currentItem.Quantity; // If percentage < 85% and total price > 1m isk then skip this item (we don't undersell) if (perc < 0.85 && total > 1000000) { Log("Not underselling item " + _currentItem.Name + " [Median buy price: " + _currentItem.InvType.MedianBuy.Value.ToString("#,##0.00") + "][Sell price: " + price.ToString("#,##0.00") + "][" + perc.ToString("0%") + "]"); sellWindow.Cancel(); State = ValueDumpState.WaitingToFinishQuickSell; break; } } // Update quantity sold _currentItem.QuantitySold += quantity; // Update station price if (!_currentItem.StationBuy.HasValue) { _currentItem.StationBuy = price; } _currentItem.StationBuy = (_currentItem.StationBuy + price) / 2; Log("Selling " + quantity + " of " + _currentItem.Name + " [Sell price: " + (price * quantity).ToString("#,##0.00") + "]" + otherPrices); sellWindow.Accept(); // Requeue to check again if (_currentItem.QuantitySold < _currentItem.Quantity) { ItemsToSell.Add(_currentItem); } _lastExecute = DateTime.Now; State = ValueDumpState.WaitingToFinishQuickSell; break; case ValueDumpState.WaitingToFinishQuickSell: if (sellWindow == null || !sellWindow.IsReady || sellWindow.Item.ItemId != _currentItem.Id) { var modal = DirectEve.Windows.FirstOrDefault(w => w.IsModal); if (modal != null) { modal.Close(); } State = ValueDumpState.NextItem; break; } break; case ValueDumpState.RefineItems: if (reprorcessingWindow == null) { if (DateTime.Now.Subtract(_lastExecute).TotalSeconds > 5) { var refineItems = hangar.Items.Where(i => ItemsToRefine.Any(r => r.Id == i.ItemId)); DirectEve.ReprocessStationItems(refineItems); _lastExecute = DateTime.Now; } return; } if (reprorcessingWindow.NeedsQuote) { if (DateTime.Now.Subtract(_lastExecute).TotalSeconds > 5) { reprorcessingWindow.GetQuotes(); _lastExecute = DateTime.Now; } return; } // Wait till we have a quote if (reprorcessingWindow.Quotes.Count == 0) { _lastExecute = DateTime.Now; return; } // Wait another 5 seconds to view the quote and then reprocess the stuff if (DateTime.Now.Subtract(_lastExecute).TotalSeconds > 5) { // TODO: We should wait for the items to appear in our hangar and then sell them... reprorcessingWindow.Reprocess(); State = ValueDumpState.Idle; } break; } }
private void OnFrame(object sender, EventArgs e) { if (State == ValueDumpState.Idle) { return; } var hangar = DirectEve.GetItemHangar(); var sellWindow = DirectEve.Windows.OfType <DirectMarketActionWindow>().FirstOrDefault(w => w.IsSellAction); switch (State) { case ValueDumpState.GetItems: if (hangar.Window == null) { // No, command it to open if (DateTime.Now.Subtract(_lastExecute).TotalSeconds > 5) { Log("Opening hangar"); DirectEve.ExecuteCommand(DirectCmd.OpenHangarFloor); _lastExecute = DateTime.Now; } return; } if (!hangar.IsReady) { return; } Log("Loading hangar items"); // Clear out the old Items.Clear(); var hangarItems = hangar.Items; if (hangarItems != null) { Items.AddRange(hangarItems.Where(i => i.ItemId > 0 && i.MarketGroupId.HasValue && i.Quantity > 0).Select(i => new ItemCache(i))); } State = ValueDumpState.UpdatePrices; break; case ValueDumpState.UpdatePrices: foreach (var item in Items) { InvType invType; if (!InvTypesById.TryGetValue(item.TypeId, out invType)) { Log("Unknown TypeId " + _currentItem.TypeId + " for " + _currentItem.Name); continue; } item.InvType = invType; } State = ValueDumpState.Idle; if (cbxSell.Checked) { // Copy the items to sell list ItemsToSell.Clear(); if (cbxUndersell.Checked) { ItemsToSell.AddRange(Items.Where(i => i.InvType != null)); } else { ItemsToSell.AddRange(Items.Where(i => i.InvType != null && i.InvType.MedianBuy.HasValue)); } State = ValueDumpState.NextItem; } break; case ValueDumpState.NextItem: if (ItemsToSell.Count == 0) { State = ValueDumpState.Idle; break; } Log(ItemsToSell.Count + " items left to sell"); _currentItem = ItemsToSell[0]; ItemsToSell.RemoveAt(0); // Dont sell containers if (_currentItem.GroupId == 448) { Log("Skipping " + _currentItem.Name); break; } State = ValueDumpState.StartQuickSell; break; case ValueDumpState.StartQuickSell: if (DateTime.Now.Subtract(_lastExecute).TotalSeconds < 1) { break; } _lastExecute = DateTime.Now; var directItem = hangar.Items.FirstOrDefault(i => i.ItemId == _currentItem.Id); if (directItem == null) { Log("Item " + _currentItem.Name + " no longer exists in the hanger"); break; } // Update Quantity _currentItem.QuantitySold = _currentItem.Quantity - (directItem.Quantity ?? _currentItem.Quantity); Log("Starting QuickSell for " + _currentItem.Name); if (!directItem.QuickSell()) { _lastExecute = DateTime.Now.AddSeconds(-5); Log("QuickSell failed for " + _currentItem.Name + ", retrying in 5 seconds"); break; } State = ValueDumpState.WaitForSellWindow; break; case ValueDumpState.WaitForSellWindow: if (sellWindow == null || !sellWindow.IsReady || sellWindow.Item.ItemId != _currentItem.Id) { break; } // Mark as new execution _lastExecute = DateTime.Now; Log("Inspecting sell order for " + _currentItem.Name); State = ValueDumpState.InspectOrder; break; case ValueDumpState.InspectOrder: // Let the order window stay open for 2 seconds if (DateTime.Now.Subtract(_lastExecute).TotalSeconds < 2) { break; } if (!sellWindow.OrderId.HasValue || !sellWindow.Price.HasValue || !sellWindow.RemainingVolume.HasValue) { Log("No order available for " + _currentItem.Name); sellWindow.Cancel(); State = ValueDumpState.WaitingToFinishQuickSell; break; } var price = sellWindow.Price.Value; if (!cbxUndersell.Checked) { if (!_currentItem.InvType.MedianBuy.HasValue) { Log("No historical price available for " + _currentItem.Name); sellWindow.Cancel(); State = ValueDumpState.WaitingToFinishQuickSell; break; } var perc = price / _currentItem.InvType.MedianBuy.Value; var total = _currentItem.InvType.MedianBuy.Value * _currentItem.Quantity; // If percentage < 85% and total price > 1m isk then skip this item (we don't undersell) if (perc < 0.85 && total > 1000000) { Log("Not underselling item " + _currentItem.Name + " [" + _currentItem.InvType.MedianBuy.Value.ToString("#,##0.00") + "][" + price.ToString("#,##0.00") + "][" + perc.ToString("0%") + "]"); sellWindow.Cancel(); State = ValueDumpState.WaitingToFinishQuickSell; break; } } var quantity = (int)Math.Min(_currentItem.Quantity - _currentItem.QuantitySold, sellWindow.RemainingVolume.Value); // Update quantity sold _currentItem.QuantitySold += quantity; // Update station price if (!_currentItem.StationBuy.HasValue) { _currentItem.StationBuy = price; } _currentItem.StationBuy = (_currentItem.StationBuy + price) / 2; Log("Selling " + quantity + " of " + _currentItem.Name + " for " + (price * quantity).ToString("#,##0.00")); sellWindow.Accept(); // Requeue to check again if (_currentItem.QuantitySold < _currentItem.Quantity) { ItemsToSell.Add(_currentItem); } _lastExecute = DateTime.Now; State = ValueDumpState.WaitingToFinishQuickSell; break; case ValueDumpState.WaitingToFinishQuickSell: if (sellWindow == null || !sellWindow.IsReady || sellWindow.Item.ItemId != _currentItem.Id) { var modal = DirectEve.Windows.FirstOrDefault(w => w.IsModal); if (modal != null) { modal.Close(); } State = ValueDumpState.NextItem; break; } break; } }
public static bool Inspectorder(string module, bool sell, bool refine, bool undersell, double RefiningEff) { // Let the order window stay open for a few seconds if (DateTime.UtcNow.Subtract(_lastExecute).TotalSeconds < Time.Instance.Marketbuyorderdelay_seconds) { return(false); } DirectMarketActionWindow sellWindow = Cache.Instance.Windows.OfType <DirectMarketActionWindow>().FirstOrDefault(w => w.IsSellAction); if (sellWindow != null && (!sellWindow.OrderId.HasValue || !sellWindow.Price.HasValue || !sellWindow.RemainingVolume.HasValue)) { Logging.Log(module, "No order available for " + _currentItem.Name, Logging.White); sellWindow.Cancel(); // // next state. // return(true); } if (sellWindow != null) { double price = sellWindow.Price.Value; int quantity = (int)Math.Min(_currentItem.Quantity - _currentItem.QuantitySold, sellWindow.RemainingVolume.Value); double totalPrice = quantity * price; string otherPrices = " "; if (_currentItem.InvType.MedianBuy.HasValue) { otherPrices += "[Median buy price: " + (_currentItem.InvType.MedianBuy.Value * quantity).ToString("#,##0.00") + "]"; } else { otherPrices += "[No median buy price]"; } if (refine) { int portions = quantity / _currentItem.PortionSize; double refinePrice = _currentItem.RefineOutput.Any() ? _currentItem.RefineOutput.Sum( m => m.Quantity * m.InvType.MedianBuy ?? 0) * portions : 0; refinePrice *= RefiningEff / 100; otherPrices += "[Refine price: " + refinePrice.ToString("#,##0.00") + "]"; if (refinePrice > totalPrice) { Logging.Log(module, "InspectRefinery [" + _currentItem.Name + "[" + quantity + "units] is worth more as mins [Refine each: " + (refinePrice / portions).ToString("#,##0.00") + "][Sell each: " + price.ToString("#,##0.00") + "][Refine total: " + refinePrice.ToString("#,##0.00") + "][Sell total: " + totalPrice.ToString("#,##0.00") + "]", Logging.White); // Add it to the refine list ItemsToRefine.Add(_currentItem); sellWindow.Cancel(); // // next state. // return(true); } } if (!undersell) { if (!_currentItem.InvType.MedianBuy.HasValue) { Logging.Log(module, "No historical price available for " + _currentItem.Name, Logging.White); sellWindow.Cancel(); // // next state. // return(true); } double perc = price / _currentItem.InvType.MedianBuy.Value; double total = _currentItem.InvType.MedianBuy.Value * _currentItem.Quantity; // If percentage < 85% and total price > 1m isk then skip this item (we don't undersell) if (perc < 0.85 && total > 1000000) { Logging.Log(module, "Not underselling item " + _currentItem.Name + Logging.Orange + " [" + Logging.White + "Median buy price: " + _currentItem.InvType.MedianBuy.Value.ToString("#,##0.00") + Logging.Orange + "][" + Logging.White + "Sell price: " + price.ToString("#,##0.00") + Logging.Orange + "][" + Logging.White + perc.ToString("0%") + Logging.Orange + "]", Logging.White); sellWindow.Cancel(); // // next state. // return(true); } } // Update quantity sold _currentItem.QuantitySold += quantity; // Update station price if (!_currentItem.StationBuy.HasValue) { _currentItem.StationBuy = price; } _currentItem.StationBuy = (_currentItem.StationBuy + price) / 2; if (sell) { Logging.Log(module, "Selling " + quantity + " of " + _currentItem.Name + Logging.Orange + " [" + Logging.White + "Sell price: " + (price * quantity).ToString("#,##0.00") + Logging.Orange + "]" + Logging.White + otherPrices, Logging.White); sellWindow.Accept(); // Update quantity sold _currentItem.QuantitySold += quantity; // Re-queue to check again if (_currentItem.QuantitySold < _currentItem.Quantity) { ItemsToSell.Add(_currentItem); } _lastExecute = DateTime.UtcNow; // // next state // return(true); } } return(true); //how would we get here with no sell window? }