Example #1
0
def execute_sync(config_file_path: Optional[str], league: str):
    try:
        # Load user config
        config_file_path = UserConfig.get_file_path(config_file_path)
        user_config = UserConfig.from_file(config_file_path, False)
    except Exception as ex:
        logging.error(f"Error: {ex.args[0]}")
        exit(1)

    if user_config.account_name == None:
        raise Exception("Missing accountName in config file")
    if user_config.poe_session_id == None:
        raise Exception("Missing POESESSID in config file")

    logging.info(
        f"Starting sync for account {user_config.account_name} in league {league}"
    )

    session = requests.Session()
    session.headers.update({
        "Cookie":
        "POESESSID={}".format(user_config.poe_session_id),
        "User-Agent":
        "curl/7.76.1"
    })

    stash_tabs = fetch_stash_tabs(session, league, user_config.account_name)
    public_tab_indices = find_public_stashes(stash_tabs)
    logging.info("Found {} public stash tabs".format(len(public_tab_indices)))

    if len(public_tab_indices) == 0:
        logging.warn("No public stash tabs to sync with were found")
        return

    items: Dict[str, int] = dict()

    for tab_idx in tqdm(public_tab_indices):
        stash_items = fetch_stash_tab_items(session, league,
                                            user_config.account_name, tab_idx)
        aggregate(items, stash_items)
        time.sleep(1)

    for item_name, stack_size in items.items():
        user_config.set_asset_quantity(item_name, stack_size)

    user_config.save(config_file_path)
    logging.info(f"Successfully synced {len(items)} items")
    def test_load_user_confg_with_correct_defaults(self):
        raw = {"version": 1, "trading": {"Chaos Orb": {}}, "assets": {}}
        raw = json.dumps(raw)
        user_config = UserConfig.from_raw(raw)
        self.assert_is_user_config(user_config)

        x = user_config.trading["Chaos Orb"]
        assert (x.minimum_stock == 0)
        assert (x.maximum_stock != 0)
        assert (type(x.sell_for) is dict)
Example #3
0
def find_paths(graph: Dict[str, Dict[str, List[Offer]]],
               have: str,
               want: str,
               user_config: UserConfig,
               max_length: int = 3) -> List[List[Offer]]:
    """
    Returns a list of all possible paths from `want` to `have` for a given graph.
    A path is simply a list of transactions between two currency nodes.
    """
    paths: deque = deque()
    correct_paths: List[List[Offer]] = []

    # If there are no paths between the specified currencies, simply abort
    if have not in graph:
        return []

    for currency in graph[have]:
        for offer in graph[have][currency]:
            paths.append([offer])

    while len(paths) > 0:
        next: List[Offer] = paths.pop()

        path_length = calculate_path_length(next)
        if path_length > max_length:
            continue

        # If a path contains an edge with a stock outside of the user-specified boundaries, prune it
        for edge in next:
            (minimum,
             maximum) = user_config.get_stock_boundaries(edge.have, edge.want)
            if edge.stock < minimum or edge.stock > maximum:
                continue

        # We have arrived at the target currency
        if next[-1].want == want:
            if is_profitable(next):
                correct_paths.append(next)
            continue

        next_currency = next[-1].want
        seen_currencies = [edge.have for edge in next]

        # If there are no paths between the specified currencies, simply skip
        if next_currency in graph:
            for currency in graph[next_currency]:
                if max_length == len(next) + 1 and currency != have:
                    continue

                if currency not in seen_currencies[1:]:
                    for offer in graph[next_currency][currency]:
                        paths.append(next + [offer])

    return correct_paths
Example #4
0
def equalize_stock_differences(path: List[Offer],
                               user_config: UserConfig) -> List[Edge]:
    """
    Finds the maximum flow for a found path and alters the conversion edges accordingly.
    Also rounds up the trading values to trade for full pieces of currency.
    """

    edges: List[Edge] = [Edge(offer, 1, 1) for offer in path]

    # Limit the first transaction's volume based on maximum trading volume
    first_edge = edges[0]
    sell_trading_cap = user_config.get_maximum_trade_volume_for_item(
        first_edge.have)
    buy_trading_cap = math.floor(first_edge.conversion_rate * sell_trading_cap)
    first_edge.stock = min(first_edge.stock, buy_trading_cap)

    # add some precalculated values
    for idx, edge in enumerate(edges):
        edge.paid = math.floor(edge.stock / edge.conversion_rate)
        edge.received = math.floor(edge.paid * edge.conversion_rate)

    # need this double loop to make sure that all stock quantity differences
    # per transaction pair are equalized. The worst case for this (starting
    # at the front of the path) is that the limiting transaction is the last one.
    # Therefore, we have to run the inner loop n times to propagate the stock
    # quantity fix towards the front of the path
    for k in range(0, len(edges)):
        for i in range(1, len(edges)):
            left = edges[i - 1]
            right = edges[i]

            if (left.received == 0 or left.paid == 0 or right.paid == 0
                    or right.received == 0):
                return []

            if left.received > right.paid:
                factor = left.received / right.paid
                left.paid = math.ceil(left.paid / factor)
                left.received = right.paid

            if left.received < right.paid:
                factor = right.paid / left.received
                right.received = math.floor(right.received / factor)
                right.paid = left.received

    return edges
Example #5
0
    def run(self):
        item_list = ItemList.load_from_file()
        user_config = UserConfig.from_file()
        # By default,
        default_backend = PoeTrade(item_list)

        params = parse_args()
        item_pairs = user_config.get_item_pairs(
        ) if params.use_filter else item_list.get_item_list_for_backend(
            default_backend, {"fullbulk": params.fullbulk})

        p = PathFinder(params.league, item_pairs, user_config)
        p.run(2)

        filename = "{}/{}".format(params.path, gen_filename())
        with open(filename, "w") as f:
            data = p.prepickle()
            f.write(data)
    def test_deserialize_user_config_with_correct_defaults(self):
        raw = {
            "version": 1,
            "trading": {
                "Chaos Orb": {}
            },
            "assets": {},
        }
        raw = json.dumps(raw)
        user_config = UserConfig.from_raw(raw)
        self.assert_is_user_config(user_config)

        x = user_config.trading["Chaos Orb"]
        assert (x.minimum_stock == 0)
        assert (x.maximum_stock != 0)
        assert (type(x.sell_for) is dict)

        self.assertEqual(user_config.poe_session_id, None)
        self.assertEqual(user_config.account_name, None)
    def test_deserialize_user_config(self):
        raw = {
            "version": 1,
            "trading": {
                "Chaos Orb": {}
            },
            "assets": {},
            "POESESSID": "123",
            "accountName": "herpderp"
        }
        raw = json.dumps(raw)
        user_config = UserConfig.from_raw(raw)
        self.assert_is_user_config(user_config)

        x = user_config.trading["Chaos Orb"]
        assert (x.minimum_stock == 0)
        assert (x.maximum_stock != 0)
        assert (type(x.sell_for) is dict)

        self.assertEqual(user_config.poe_session_id, "123")
        self.assertEqual(user_config.account_name, "herpderp")
Example #8
0
 def test_load_default_user_confg_from_fs(self):
     user_config: UserConfig = UserConfig.from_file()
     self.assert_is_user_config(user_config)
init_logger(arguments.debug)
item_list = ItemList.load_from_file()
backend = PoeOfficial(item_list)

league = arguments.league
currency = arguments.currency
limit = arguments.limit
fullbulk = arguments.fullbulk
no_filter = arguments.nofilter
config = {"fullbulk": fullbulk}

# Load excluded trader list
excluded_traders = load_excluded_traders()

# Load user config
user_config = UserConfig.from_file()

# Load item pairs
item_pairs = item_list.get_item_list_for_backend(
    backend, config) if no_filter else user_config.get_item_pairs()

p = PathFinder(league, item_pairs, user_config, excluded_traders)
p.run(2)

try:
    logging.info("\n")
    if currency == "all":
        for c in p.graph.keys():
            log_conversions(p.results, c, limit)
    else:
        log_conversions(p.results, currency, limit)
Example #10
0
# global arguments
command: str = arguments.command
league: str = arguments.league
config_file_path: Union[str, None] = arguments.config

if command == "pathfinding":
    # arguments related to pathfinding
    currency: Union[str, None] = arguments.currency
    limit: Union[int, None] = arguments.limit
    fullbulk: bool = arguments.fullbulk
    no_filter: bool = arguments.nofilter
    config = {"fullbulk": fullbulk}

    try:
        # Load user config
        user_config = UserConfig.from_file(config_file_path, True)
    except Exception as ex:
        logging.error(f"Error: {ex.args[0]}")
        exit(1)

    # Load excluded trader list
    excluded_traders = load_excluded_traders()

    # Load item pairs
    item_list = ItemList.load_from_file()
    backend = PoeOfficial(item_list)
    item_pairs = item_list.get_item_list_for_backend(
        backend, config) if no_filter else user_config.get_item_pairs()

    execute_pathfinding(currency, league, limit, item_pairs, user_config,
                        excluded_traders)
                         league=LEAGUE,
                         stock=1576),
             paid=96,
             received=66),
        Edge(offer=Offer(contact_ign="MVP_Kefir",
                         want="Chaos",
                         have="Chromatic",
                         conversion_rate=0.087,
                         league=LEAGUE,
                         stock=20),
             paid=66,
             received=5),
    ],
}

user_config = UserConfig.from_file(DEFAULT_CONFIG_DEFAULT_FILE_PATH)


class GraphTest(unittest.TestCase):
    def test_build_graph(self):
        graph = build_graph(test_offers)
        self.assertDictEqual(graph, expected_graph)

    def test_find_paths(self):
        paths_small_same_currency = find_paths(expected_graph_small, "Chaos",
                                               "Chaos", user_config)
        self.assertListEqual(expected_profitable_paths_small_same_currency(),
                             paths_small_same_currency)

    def test_is_profitable(self):
        path = expected_paths_small_same_currency()[0]
 def test_load_default_user_config_from_file(self):
     user_config = UserConfig.from_file(DEFAULT_CONFIG_DEFAULT_FILE_PATH)
     self.assert_is_user_config(user_config)