|
|
@@ -7,9 +7,9 @@ import typing
|
|
|
import cache
|
|
|
|
|
|
def main() -> None:
|
|
|
- recipes: list[Recipe] = cache.get('https://api.prunplanner.org/data/recipes')
|
|
|
- buildings: dict[str, Building] = {m['Ticker']: m for m in cache.get('https://api.prunplanner.org/data/buildings')}
|
|
|
- materials: dict[str, Material] = {m['Ticker']: m for m in cache.get('https://api.prunplanner.org/data/materials')}
|
|
|
+ recipes: list[Recipe] = cache.get('https://api.prunplanner.org/data/recipes/')
|
|
|
+ buildings: dict[str, Building] = {m['building_ticker']: m for m in cache.get('https://api.prunplanner.org/data/buildings/')}
|
|
|
+ materials: dict[str, Material] = {m['ticker']: m for m in cache.get('https://api.prunplanner.org/data/materials/')}
|
|
|
raw_prices: list[RawPrice] = cache.get('https://refined-prun.github.io/refined-prices/all.json')
|
|
|
for cx in ['AI1', 'CI1', 'IC1', 'NC1']:
|
|
|
profits = calc_for_cx(cx, recipes, buildings, materials, raw_prices)
|
|
|
@@ -23,16 +23,16 @@ def calc_for_cx(cx: str, recipes: typing.Collection[Recipe], buildings: typing.M
|
|
|
if p['ExchangeCode'] == cx
|
|
|
}
|
|
|
habitation: typing.Mapping[Worker, str] = {
|
|
|
- 'Pioneers': 'HB1',
|
|
|
- 'Settlers': 'HB2',
|
|
|
- 'Technicians': 'HB3',
|
|
|
- 'Engineers': 'HB4',
|
|
|
- 'Scientists': 'HB5',
|
|
|
+ 'pioneers': 'HB1',
|
|
|
+ 'settlers': 'HB2',
|
|
|
+ 'technicians': 'HB3',
|
|
|
+ 'engineers': 'HB4',
|
|
|
+ 'scientists': 'HB5',
|
|
|
}
|
|
|
hab_area_cost: dict[Worker, float] = {}
|
|
|
hab_capex: dict[Worker, float] = {}
|
|
|
for worker, hab in habitation.items():
|
|
|
- hab_area_cost[worker] = buildings[hab]['AreaCost'] / 100
|
|
|
+ hab_area_cost[worker] = buildings[hab]['area_cost'] / 100
|
|
|
hab_capex[worker] = building_construction_cost(buildings[hab], prices) / 100
|
|
|
|
|
|
profits: list[Profit] = []
|
|
|
@@ -45,51 +45,51 @@ def calc_for_cx(cx: str, recipes: typing.Collection[Recipe], buildings: typing.M
|
|
|
def calc_profit(recipe: Recipe, buildings: typing.Mapping[str, Building], hab_area_cost: typing.Mapping[Worker, float],
|
|
|
hab_capex: typing.Mapping[Worker, float], materials: typing.Mapping[str, Material],
|
|
|
prices: typing.Mapping[str, Price]) -> Profit | None:
|
|
|
- if len(recipe['Outputs']) == 0:
|
|
|
+ if len(recipe['outputs']) == 0:
|
|
|
return
|
|
|
|
|
|
outputs: list[MatPrice] = []
|
|
|
revenue = 0
|
|
|
output_prices: dict[str, PriceNonNull] = {}
|
|
|
- for output in recipe['Outputs']:
|
|
|
- price = prices[output['Ticker']]
|
|
|
+ for output in recipe['outputs']:
|
|
|
+ price = prices[output['material_ticker']]
|
|
|
if price.vwap_7d is None or price.average_traded_7d is None:
|
|
|
return # skip recipes with thinly traded outputs
|
|
|
- output_prices[output['Ticker']] = typing.cast(PriceNonNull, price)
|
|
|
- outputs.append(MatPrice(output['Ticker'], output['Amount'], price.vwap_7d))
|
|
|
- revenue += price.vwap_7d * output['Amount']
|
|
|
+ output_prices[output['material_ticker']] = typing.cast(PriceNonNull, price)
|
|
|
+ outputs.append(MatPrice(output['material_ticker'], output['material_amount'], price.vwap_7d))
|
|
|
+ revenue += price.vwap_7d * output['material_amount']
|
|
|
|
|
|
input_costs: list[MatPrice] = []
|
|
|
cost = 0
|
|
|
- for input in recipe['Inputs']:
|
|
|
- if (input_cost := prices[input['Ticker']].vwap_7d) is None:
|
|
|
+ for input in recipe['inputs']:
|
|
|
+ if (input_cost := prices[input['material_ticker']].vwap_7d) is None:
|
|
|
return # skip recipes with thinly traded inputs
|
|
|
- input_costs.append(MatPrice(input['Ticker'], input['Amount'], input_cost))
|
|
|
- cost += input_cost * input['Amount']
|
|
|
+ input_costs.append(MatPrice(input['material_ticker'], input['material_amount'], input_cost))
|
|
|
+ cost += input_cost * input['material_amount']
|
|
|
profit_per_run = revenue - cost
|
|
|
|
|
|
- building = buildings[recipe['BuildingTicker']]
|
|
|
- area = building['AreaCost'] + sum(hab_area_cost[worker] * building[worker] for worker in hab_area_cost)
|
|
|
+ building = buildings[recipe['building_ticker']]
|
|
|
+ area = building['area_cost'] + sum(hab_area_cost[worker] * building[worker] for worker in hab_area_cost)
|
|
|
capex = building_construction_cost(building, prices) + \
|
|
|
sum(hab_capex[worker] * building[worker] for worker in hab_capex)
|
|
|
- runs_per_day = 24 * 60 * 60 * 1000 / recipe['TimeMs']
|
|
|
- if building['Ticker'] in ('FRM', 'ORC'):
|
|
|
+ runs_per_day = 24 * 60 * 60 * 1000 / recipe['time_ms']
|
|
|
+ if building['building_ticker'] in ('FRM', 'ORC'):
|
|
|
runs_per_day *= 1.1212 # promitor's fertility
|
|
|
worker_consumable_daily_cost = building_daily_cost(building, prices)
|
|
|
cost_per_day = cost * runs_per_day + worker_consumable_daily_cost
|
|
|
|
|
|
- lowest_liquidity = min(recipe['Outputs'],
|
|
|
- key=lambda output: output['Amount'] / output_prices[output['Ticker']].average_traded_7d)
|
|
|
- output_per_day = lowest_liquidity['Amount'] * runs_per_day
|
|
|
+ lowest_liquidity = min(recipe['outputs'],
|
|
|
+ key=lambda output: output['material_amount'] / output_prices[output['material_ticker']].average_traded_7d)
|
|
|
+ output_per_day = lowest_liquidity['material_amount'] * runs_per_day
|
|
|
|
|
|
logistics_per_area = max(
|
|
|
- sum(materials[input['Ticker']]['Weight'] * input['Amount'] for input in recipe['Inputs']),
|
|
|
- sum(materials[input['Ticker']]['Volume'] * input['Amount'] for input in recipe['Inputs']),
|
|
|
- sum(materials[output['Ticker']]['Weight'] * output['Amount'] for output in recipe['Outputs']),
|
|
|
- sum(materials[output['Ticker']]['Volume'] * output['Amount'] for output in recipe['Outputs']),
|
|
|
+ sum(materials[input['material_ticker']]['weight'] * input['material_amount'] for input in recipe['inputs']),
|
|
|
+ sum(materials[input['material_ticker']]['volume'] * input['material_amount'] for input in recipe['inputs']),
|
|
|
+ sum(materials[output['material_ticker']]['weight'] * output['material_amount'] for output in recipe['outputs']),
|
|
|
+ sum(materials[output['material_ticker']]['volume'] * output['material_amount'] for output in recipe['outputs']),
|
|
|
) * runs_per_day / area
|
|
|
- return Profit(outputs, recipe['RecipeName'],
|
|
|
- expertise=building['Expertise'],
|
|
|
+ return Profit(outputs, recipe['recipe_name'],
|
|
|
+ expertise=building['expertise'],
|
|
|
profit_per_day=(profit_per_run * runs_per_day - worker_consumable_daily_cost),
|
|
|
area=area,
|
|
|
capex=capex,
|
|
|
@@ -99,18 +99,18 @@ def calc_profit(recipe: Recipe, buildings: typing.Mapping[str, Building], hab_ar
|
|
|
runs_per_day=runs_per_day,
|
|
|
logistics_per_area=logistics_per_area,
|
|
|
output_per_day=output_per_day,
|
|
|
- average_traded_7d=output_prices[lowest_liquidity['Ticker']].average_traded_7d)
|
|
|
+ average_traded_7d=output_prices[lowest_liquidity['material_ticker']].average_traded_7d)
|
|
|
|
|
|
def building_construction_cost(building: Building, prices: typing.Mapping[str, Price]) -> float:
|
|
|
- return sum(bc['Amount'] * prices[bc['CommodityTicker']].vwap_7d for bc in building['BuildingCosts']) # pyright: ignore[reportOperatorIssue]
|
|
|
+ return sum(bc['material_amount'] * prices[bc['material_ticker']].vwap_7d for bc in building['costs']) # pyright: ignore[reportOperatorIssue]
|
|
|
|
|
|
def building_daily_cost(building: Building, prices: typing.Mapping[str, Price]) -> float:
|
|
|
consumption = {
|
|
|
- 'Pioneers': [('COF', 0.5), ('DW', 4), ('RAT', 4), ('OVE', 0.5), ('PWO', 0.2)],
|
|
|
- 'Settlers': [('DW', 5), ('RAT', 6), ('KOM', 1), ('EXO', 0.5), ('REP', 0.2), ('PT', 0.5)],
|
|
|
- 'Technicians': [('DW', 7.5), ('RAT', 7), ('ALE', 1), ('MED', 0.5), ('SC', 0.1), ('HMS', 0.5), ('SCN', 0.1)],
|
|
|
- 'Engineers': [('DW', 10), ('MED', 0.5), ('GIN', 1), ('FIM', 7), ('VG', 0.2), ('HSS', 0.2), ('PDA', 0.1)],
|
|
|
- 'Scientists': [('DW', 10), ('MED', 0.5), ('WIN', 1), ('MEA', 7), ('NST', 0.1), ('LC', 0.2), ('WS', 0.1)],
|
|
|
+ 'pioneers': [('COF', 0.5), ('DW', 4), ('RAT', 4), ('OVE', 0.5), ('PWO', 0.2)],
|
|
|
+ 'settlers': [('DW', 5), ('RAT', 6), ('KOM', 1), ('EXO', 0.5), ('REP', 0.2), ('PT', 0.5)],
|
|
|
+ 'technicians': [('DW', 7.5), ('RAT', 7), ('ALE', 1), ('MED', 0.5), ('SC', 0.1), ('HMS', 0.5), ('SCN', 0.1)],
|
|
|
+ 'engineers': [('DW', 10), ('MED', 0.5), ('GIN', 1), ('FIM', 7), ('VG', 0.2), ('HSS', 0.2), ('PDA', 0.1)],
|
|
|
+ 'scientists': [('DW', 10), ('MED', 0.5), ('WIN', 1), ('MEA', 7), ('NST', 0.1), ('LC', 0.2), ('WS', 0.1)],
|
|
|
}
|
|
|
cost = 0
|
|
|
for worker, mats in consumption.items():
|
|
|
@@ -120,38 +120,38 @@ def building_daily_cost(building: Building, prices: typing.Mapping[str, Price])
|
|
|
cost += (mat_price.vwap_7d or mat_price.vwap_30d) * workers * per_100 / 100
|
|
|
return cost
|
|
|
|
|
|
-Worker = typing.Literal['Pioneers', 'Settlers', 'Technicians', 'Engineers', 'Scientists']
|
|
|
+Worker = typing.Literal['pioneers', 'settlers', 'technicians', 'engineers', 'scientists']
|
|
|
|
|
|
class Recipe(typing.TypedDict):
|
|
|
- RecipeName: str
|
|
|
- BuildingTicker: str
|
|
|
- Inputs: list[RecipeMat]
|
|
|
- Outputs: list[RecipeMat]
|
|
|
- TimeMs: int
|
|
|
+ recipe_name: str
|
|
|
+ building_ticker: str
|
|
|
+ inputs: list[RecipeMat]
|
|
|
+ outputs: list[RecipeMat]
|
|
|
+ time_ms: int
|
|
|
|
|
|
class RecipeMat(typing.TypedDict):
|
|
|
- Ticker: str
|
|
|
- Amount: int
|
|
|
+ material_ticker: str
|
|
|
+ material_amount: int
|
|
|
|
|
|
class Building(typing.TypedDict):
|
|
|
- Ticker: str
|
|
|
- Expertise: str
|
|
|
- AreaCost: int
|
|
|
- BuildingCosts: list[BuildingMat]
|
|
|
- Pioneers: int
|
|
|
- Settlers: int
|
|
|
- Technicians: int
|
|
|
- Engineers: int
|
|
|
- Scientists: int
|
|
|
+ building_ticker: str
|
|
|
+ expertise: str
|
|
|
+ area_cost: int
|
|
|
+ costs: list[BuildingMat]
|
|
|
+ pioneers: int
|
|
|
+ settlers: int
|
|
|
+ technicians: int
|
|
|
+ engineers: int
|
|
|
+ scientists: int
|
|
|
|
|
|
class BuildingMat(typing.TypedDict):
|
|
|
- CommodityTicker: str
|
|
|
- Amount: int
|
|
|
+ material_ticker: str
|
|
|
+ material_amount: int
|
|
|
|
|
|
class Material(typing.TypedDict):
|
|
|
- Ticker: str
|
|
|
- Weight: float
|
|
|
- Volume: float
|
|
|
+ ticker: str
|
|
|
+ weight: float
|
|
|
+ volume: float
|
|
|
|
|
|
class RawPrice(typing.TypedDict):
|
|
|
MaterialTicker: str
|