From acbf6d6bd6d63ab0e9f7c4e119827f76e0382aac Mon Sep 17 00:00:00 2001 From: kboz Date: Sun, 19 Apr 2026 01:50:32 +0200 Subject: feat(backend): unify boot process and refactor route properties - Added scripts/haul.sh, setup_auth.py, and setup_eve_data.py for simplified SSO and CSV data bootstrapping. - Refactored `Ship` and `RouteStep` properties across route planning modules to utilize dictionaries instead of strict dataclass attributes. - Re-aligned route limits, reducing upfront capital risk values in `arbitrage.py` and updating ship metrics in `manager.py`. - Updated `.gitignore`, `.env.example`, and created AI-assistant prompt configuration. - Added comprehensive "Getting Started" guides to the README and initialized CHANGELOG.md. --- backend/src/arbitrage.py | 2 +- backend/src/graph.py | 1 + backend/src/loader.py | 5 ++++- backend/src/manager.py | 31 ++++++++++++++++++------------- backend/src/pathfinder.py | 4 ++-- backend/src/route.py | 31 +++++++++++++------------------ 6 files changed, 39 insertions(+), 35 deletions(-) (limited to 'backend') diff --git a/backend/src/arbitrage.py b/backend/src/arbitrage.py index 0991bbc..c1a0459 100644 --- a/backend/src/arbitrage.py +++ b/backend/src/arbitrage.py @@ -9,7 +9,7 @@ logger = logging.getLogger(__name__) TAX_RATE = 0.08 PROFIT_THRESHOLD = 100_000 -MAX_CAPITAL = 100_000_000 +MAX_CAPITAL = 20_000_000 SNIPE_PROFIT_THRESHOLD = 20_000_000 @dataclass diff --git a/backend/src/graph.py b/backend/src/graph.py index 31eef80..9e4534a 100644 --- a/backend/src/graph.py +++ b/backend/src/graph.py @@ -300,6 +300,7 @@ class NavigationGraph: else: logger.info("Generating path lengths and caching to file") dist = dict(nx.all_pairs_dijkstra_path_length(self.graph)) + PATHS_FILE.parent.mkdir(parents=True, exist_ok=True) with PATHS_FILE.open("wb") as f: pickle.dump(dist, f) return dist diff --git a/backend/src/loader.py b/backend/src/loader.py index 7e536c1..2d46cd6 100644 --- a/backend/src/loader.py +++ b/backend/src/loader.py @@ -96,7 +96,10 @@ def process_row( item_id_int = int(item_id) type_id_int = int(type_id) group_id_int = int(group_id) - solar_system_id_int = int(solar_system_id) + + solar_system_id_int = None + if solar_system_id and solar_system_id != 'None': + solar_system_id_int = int(solar_system_id) if type_id_int == TYPE_ID_SOLAR_SYSTEM: solar_systems[item_id_int] = { diff --git a/backend/src/manager.py b/backend/src/manager.py index 03df5d8..09d920e 100644 --- a/backend/src/manager.py +++ b/backend/src/manager.py @@ -1,6 +1,6 @@ import threading -from graph import Graph +from graph import NavigationGraph from esi.api import get_location, set_waypoints, open_market_window from market import Market from arbitrage import arbitrage, snipe @@ -14,15 +14,15 @@ class Manager: def __init__(self): self.ship = { "location": get_location(), - "cargo": 600, - "max_warp_speed": 8.22, # AU/s - "max_subwarp_speed": 216.5, # m/s + "cargo": 4000, + "max_warp_speed": 4.55, # AU/s + "max_subwarp_speed": 166.9, # m/s "gankers_areas": {"Ahbazon": 0.5}, #["Miroitem", "Rancer", "Huola", "Ahbazon", "Uedama", "Sivala", "Tama", "Onatoh"], "player_cost": 15_000_000 / 3600, # isk/second "risk_cost": 60_000_000, # isk - "ship_cost": 50_000_000 # isk + "ship_cost": 5_500_000 # isk } - self.graph = Graph(self.ship) + self.graph = NavigationGraph(self.ship) self.route = [] self.route_info = {} self.market = Market() @@ -51,12 +51,12 @@ class Manager: potential_snipe = snipe(self.market.orders, self.ship["cargo"], current_region) if potential_snipe: self.log.append("----------------") - self.log.append("Snipe: " + str(potential_snipe[1]) + " orders for " + str(potential_snipe[0]) + " ISK") + self.log.append(f"Snipe: {potential_snipe.item_name} orders for {potential_snipe.gross_profit} ISK") self.log.append("----------------") - print("snipe possible", potential_snipe[0], "ISK", potential_snipe[1]) + print("snipe possible", potential_snipe.gross_profit, "ISK", potential_snipe.item_name) - open_market_window(potential_snipe[1]["type_id"]) + open_market_window(potential_snipe.type_id) def update(self): @@ -82,8 +82,9 @@ class Manager: def target_function(log): try: - updated_regions = self.market.update_orders(log) + updated_regions = self.market.update_orders() if updated_regions: + log.append(f"Updated {len(updated_regions)} market regions") self.snipe_callback(updated_regions) finally: self.updating_orders = False @@ -97,8 +98,12 @@ class Manager: order_matches = pathfinder(order_matches, self.graph, self.ship) self.route, self.route_info = route.route(order_matches, self.graph, self.ship) - set_waypoints([r["location_id"] for r in self.route[1:]]) - - print(self.route) + if self.route: + set_waypoints([r["location_id"] for r in self.route[1:]]) + print(self.route) + else: + self.route = [] + self.route_info = {} + print("No profitable route found yet.") \ No newline at end of file diff --git a/backend/src/pathfinder.py b/backend/src/pathfinder.py index 80e7a44..4ce2df3 100644 --- a/backend/src/pathfinder.py +++ b/backend/src/pathfinder.py @@ -3,7 +3,7 @@ from dataclasses import dataclass from tqdm import tqdm from arbitrage import Trade -from graph import Graph +from graph import NavigationGraph as Graph logging.basicConfig(level=logging.INFO) logger = logging.getLogger(__name__) @@ -111,7 +111,7 @@ def calculate_net_profit(order_matches: list[Trade], graph: Graph, ship: Ship) - for order_match in tqdm(order_matches): try: # Calculate transport cost from ship location to from_station - cost_to_source = graph.shortest_path_length(ship.location, order_match.from_station) + cost_to_source = graph.shortest_path_length(ship["location"], order_match.from_station) # Calculate transport cost from from_station to to_station cost_to_destination = graph.shortest_path_length(order_match.from_station, order_match.to_station) diff --git a/backend/src/route.py b/backend/src/route.py index ec099b1..2bcae7e 100644 --- a/backend/src/route.py +++ b/backend/src/route.py @@ -4,9 +4,10 @@ from typing import Optional from tqdm import tqdm -from graph import Graph +from graph import NavigationGraph as Graph from pathfinder import Ship from arbitrage import Trade +from typing import Any logging.basicConfig(level=logging.INFO) logger = logging.getLogger(__name__) @@ -14,13 +15,7 @@ logger = logging.getLogger(__name__) MAX_TRADES_TO_CONSIDER = 20_000 MAX_CAPITAL = 100_000_000 -@dataclass -class RouteStep: - location_id: int - station_name: str - actions: list[dict] = field(default_factory=list) - -Route = list[RouteStep] +Route = list[dict[str, Any]] def route(trades: list[Trade], graph: Graph, ship: Ship) -> tuple[Optional[Route], Optional[dict]]: """ @@ -46,7 +41,7 @@ def route(trades: list[Trade], graph: Graph, ship: Ship) -> tuple[Optional[Route seen_routes = set() for trade in tqdm(trades[:MAX_TRADES_TO_CONSIDER], desc="Evaluating trades"): - route_stations = (ship.location, trade.from_station, trade.to_station) + route_stations = (ship["location"], trade.from_station, trade.to_station) if route_stations in seen_routes: continue @@ -59,7 +54,7 @@ def route(trades: list[Trade], graph: Graph, ship: Ship) -> tuple[Optional[Route continue try: - path = graph.shortest_path(ship.location, trade.from_station)[:-1] + path = graph.shortest_path(ship["location"], trade.from_station)[:-1] path += graph.shortest_path(trade.from_station, trade.to_station) except Exception as e: logger.error(f"Error finding path: {e}") @@ -68,7 +63,7 @@ def route(trades: list[Trade], graph: Graph, ship: Ship) -> tuple[Optional[Route risk = sum(graph.graph[u][v]['risk'] for u, v in zip(path, path[1:])) transport_time = sum(graph.graph[u][v]['time'] for u, v in zip(path, path[1:])) - capital = getattr(ship, 'ship_cost', 0.0) + sum(t.from_price * t.quantity for t in optimized_trades) + capital = ship.get('ship_cost', 0.0) + sum(t.from_price * t.quantity for t in optimized_trades) if transport_time == 0: logger.warning("Transport time is zero, skipping this route to avoid division by zero.") @@ -133,7 +128,7 @@ def select_trades(stations: list[int], trades: list[Trade], ship: Ship) -> list[ from_remaining = used_orders.get(from_order, quantity) to_remaining = used_orders.get(to_order, quantity) - max_quantity_by_cargo = int((ship.cargo - cargo) // trade.item_cargo_volume) + max_quantity_by_cargo = int((ship["cargo"] - cargo) // trade.item_cargo_volume) max_quantity_by_capital = int((MAX_CAPITAL - capital) // trade.from_price) max_quantity = min(quantity, from_remaining, to_remaining, max_quantity_by_cargo, max_quantity_by_capital) @@ -165,7 +160,7 @@ def select_trades(stations: list[int], trades: list[Trade], ship: Ship) -> list[ optimized_trades.append(updated_trade) - if cargo >= ship.cargo or capital >= MAX_CAPITAL: + if cargo >= ship["cargo"] or capital >= MAX_CAPITAL: break return optimized_trades @@ -184,8 +179,8 @@ def set_actions(route: Route, trades: list[Trade]) -> Route: bought_items = set() for trade in trades: for step in route: - if trade.from_station == step.location_id: - step.actions.append({ + if trade.from_station == step["location_id"]: + step["actions"].append({ "action_type": "buy", "item": trade.item_name, "type_id": trade.type_id, @@ -193,8 +188,8 @@ def set_actions(route: Route, trades: list[Trade]) -> Route: "price": trade.from_price, }) bought_items.add(trade.type_id) - if trade.to_station == step.location_id and trade.type_id in bought_items: - step.actions.append({ + if trade.to_station == step["location_id"] and trade.type_id in bought_items: + step["actions"].append({ "action_type": "sell", "item": trade.item_name, "type_id": trade.type_id, @@ -203,6 +198,6 @@ def set_actions(route: Route, trades: list[Trade]) -> Route: }) for step in route: - step.actions.sort(key=lambda action: (action["action_type"], action["item"], action["price"])) + step["actions"].sort(key=lambda action: (action["action_type"], action["item"], action["price"])) return route -- cgit v1.3