I Need To Be Cancelled

in Synergy Builders9 days ago

I know, I know... I haven't been posting every little thing that I'm working on but here is where I'm at right now.

Working on these trading bots has become a deeper hole than I even expected. The orders pile up and money sits and stagnates, so I'm working on trying to incorporate a cancel orders idea into everything but I've hit a damn road block.

So I'm working on this mass cancel order bot.... here


import time
import requests
import json as jsonlib 
from nectar.hive import Hive
from beem import Hive 
from nectar.account import Account
from nectar.transactionbuilder import TransactionBuilder
from nectarbase.operations import Custom_json
from beembase.operations import Custom_json
from nectar.instance import set_shared_blockchain_instance
import json as jsonlib

# CONFIG - fill these in with your account and keys
ACCOUNT = "Your Username"  # Your Hive account
HIVE_ACTIVE_KEY = "YOUR KEY"  # Your Hive active key
HIVE_NODES = [
    "https://api.hive.blog",
    "https://anyx.io",
    "https://api.openhive.network",
]
# Only include reliable, working Hive-Engine nodes. Update as needed if nodes go down.
ENGINE_NODES = [
    "https://api.hive-engine.com/rpc/contracts",
    "https://api2.hive-engine.com/rpc/contracts",
    "https://herpc.dtools.dev/rpc/contracts"
]

CANCEL_DELAY = 5  # seconds between cancels

def get_open_orders(account_name):
    """Fetch open orders from Hive-Engine openOrders table."""
    for node in ENGINE_NODES:
        payload = {
            "jsonrpc": "2.0",
            "method": "find",  # Use 'find' for /rpc/contracts
            "params": {
                "contract": "market",
                "table": "openOrders",
                "query": {"account": account_name},
                "limit": 1000
            },
            "id": 1
        }
        try:
            print(f"[DEBUG] Payload to {node}: {payload}")
            resp = requests.post(node, json=payload, timeout=10)
            print(f"[DEBUG] Raw response from {node}: {resp.text}")
            if resp.status_code == 200:
                data = resp.json()
                orders = data.get('result')
                if not isinstance(orders, list):
                    orders = []
                if orders:
                    print(f"[ENGINE] {len(orders)} open orders found at {node}")
                    return orders
            else:
                print(f"[ENGINE] Error: {resp.status_code} at {node}")
        except Exception as e:
            print(f"[ENGINE] Exception: {e}")
    print("[ENGINE] No open orders found on any node.")
    return []

def extract_order_id(order):
    if 'orderId' in order:
        return str(order['orderId'])
    raise ValueError(f"Order missing orderId: {order}")

def cancel_order(account_name, order, active_key, nodes=HIVE_NODES):
    # Use correct payload depending on order dict fields
    if 'type' in order and '_id' in order:
        payload = [{
            "contractName": "market",
            "contractAction": "cancel",
            "contractPayload": {
                "type": order["type"],
                "id": str(order["_id"])
            }
        }]
    elif 'orderId' in order:
        payload = {
            "contractName": "market",
            "contractAction": "cancel",
            "contractPayload": {
                "orderId": str(order["orderId"])
            }
        }
    else:
        print("[CANCEL ERROR] Order missing required fields for cancellation:", order)
        return False

    for node in nodes:
        try:
            hive = Hive(node=node, keys=[active_key])
            tx = TransactionBuilder(blockchain_instance=hive)
            op = Custom_json(
                required_auths=[account_name],
                required_posting_auths=[],
                id="ssc-mainnet-hive",
                json=jsonlib.dumps(payload),
            )
            tx.appendOps([op])
            tx.appendSigner(account_name, "active")
            tx.sign()
            broadcast_result = tx.broadcast()
            print(f"[CANCEL DEBUG] Broadcast result: {broadcast_result}")
            tx_id = None
            if isinstance(broadcast_result, dict):
                tx_id = (
                    broadcast_result.get('id') or
                    broadcast_result.get('txid') or
                    broadcast_result.get('transaction_id') or
                    (broadcast_result.get('result') and (
                        broadcast_result['result'].get('id') or
                        broadcast_result['result'].get('txid') or
                        broadcast_result['result'].get('transaction_id')
                    ))
                )
            if isinstance(broadcast_result, dict) and broadcast_result.get('error'):
                print(f"[CANCEL ERROR] {broadcast_result['error']}")
                continue
            print(f"[CANCEL] Success! TXID: {tx_id}")
            return True
        except Exception as e:
            print(f"[CANCEL ERROR] Exception: {e}")
            continue
    print("[CANCEL] All nodes failed to broadcast cancel order.")
    return False

def print_all_open_orders(account_name):
    open_orders = get_open_orders(account_name)
    if not open_orders:
        print(f"[INFO] No open orders found for {account_name}.")
        return
    print(f"[INFO] Open orders for {account_name}:")
    for order in open_orders:
        print(order)
    print(f"[INFO] Total open orders: {len(open_orders)}")

def get_book_orders(account_name):
    """Fetch orders from buyBook and sellBook tables for debugging."""
    for table in ["buyBook", "sellBook"]:
        for node in ENGINE_NODES:
            payload = {
                "jsonrpc": "2.0",
                "method": "find",
                "params": {
                    "contract": "market",
                    "table": table,
                    "query": {"account": account_name},
                    "limit": 1000
                },
                "id": 1
            }
            try:
                print(f"[DEBUG] Payload to {node} ({table}): {payload}")
                resp = requests.post(node, json=payload, timeout=10)
                print(f"[DEBUG] Raw response from {node} ({table}): {resp.text}")
                if resp.status_code == 200:
                    data = resp.json()
                    orders = data.get('result')
                    if orders:
                        print(f"[ENGINE] {len(orders)} orders found in {table} at {node}")
                        for order in orders:
                            print(order)
            except Exception as e:
                print(f"[ENGINE] Exception: {e}")

def get_all_book_orders(account_name):
    """Fetch all orders from buyBook and sellBook tables for cancellation."""
    all_orders = []
    for table in ["buyBook", "sellBook"]:
        for node in ENGINE_NODES:
            payload = {
                "jsonrpc": "2.0",
                "method": "find",
                "params": {
                    "contract": "market",
                    "table": table,
                    "query": {"account": account_name},
                    "limit": 1000
                },
                "id": 1
            }
            try:
                resp = requests.post(node, json=payload, timeout=10)
                if resp.status_code == 200:
                    data = resp.json()
                    orders = data.get('result')
                    if orders:
                        all_orders.extend(orders)
                        print(f"[ENGINE] {len(orders)} orders found in {table} at {node}")
                        break  # Only use the first working node for each table
            except Exception as e:
                print(f"[ENGINE] Exception: {e}")
    return all_orders

def find_eldest_order(orders):
    # Prefer to sort by 'timestamp' if present, else by '_id' (string sort is fine for ObjectId)
    if not orders:
        return None
    if all('timestamp' in o for o in orders):
        return min(orders, key=lambda o: o['timestamp'])
    return min(orders, key=lambda o: o['_id'])

def main():
    print(f"[INFO] Fetching all open orders for {ACCOUNT} from buyBook and sellBook")
    all_orders = get_all_book_orders(ACCOUNT)
    if not all_orders:
        print("[INFO] No open orders to cancel.")
        return
    eldest = find_eldest_order(all_orders)
    if not eldest:
        print("[INFO] No valid order found to cancel.")
        return
    print(f"[INFO] Cancelling eldest order _id: {eldest.get('_id')}\n{eldest}")
    try:
        cancel_order(ACCOUNT, eldest, HIVE_ACTIVE_KEY)
    except Exception as e:
        print(f"[ERROR] {e}")
    print("[INFO] Done.")

if __name__ == "__main__":
    print_all_open_orders(ACCOUNT)
    print("\n[INFO] Checking buyBook and sellBook tables for debugging...")
    get_book_orders(ACCOUNT)
    print("\n[INFO] Cancelling all orders from buyBook and sellBook...")
    main()


Then all I get is his blockchain reply...


id: ssc-mainnet-hive
json: {
  "contractName": "market",
  "contractAction": "cancel",
  "contractPayload": {
    "orderId": "95392552"
  }
}
required_auths: [
  "paulmoon410"
]
required_posting_auths: []

@thecrazygm @powerpaul @ecoinstant @enginewitty @neoxian - Appreciate any help as always.

Sort:  

Thank you asking. A honor to be mentioned. That is interesting, but I would need to recreate it. Maybe I could find this weekend for it - but no guarantee. Do you have a git with the project? If you prefer, via Discord PM too.

I do have GitHub projects and repositories, same username.

The only thing that jumps out at me is that one of them you are sending a list [] and the other one you are sending a dict {}, which should be also be a list in:

    if 'type' in order and '_id' in order:
        payload = [{
            "contractName": "market",
            "contractAction": "cancel",
            "contractPayload": {
                "type": order["type"],
                "id": str(order["_id"])
            }
        }]
    elif 'orderId' in order:
        payload = { # <-- This one is missing the [
            "contractName": "market",
            "contractAction": "cancel",
            "contractPayload": {
                "orderId": str(order["orderId"])
            }
        } # <--- and the closing ]
    else:
        print("[CANCEL ERROR] Order missing required fields for cancellation:", order)
        return False

Everything shut down when my main computer updated. I'm going to have to make a script to run the trading bots on booting of the Pi's I have. I'll check my code out as soon as I can.

Would it be easier to give them expiration dates? Say different increments. A ten minute one, ten hour, ten day, however you want to set it up. A variable though, so can be changed easily by the trader.

!PIMP
!PAKX
!DUO

I could try to put a time limit on it. Sometimes thats not as profitable. I really want the oldest orders to cancel before new ones are placed. I'm a bit behind on the workload...but I'm on it.


You just got DUO from @enginewitty.
They have 1/1 DUO calls left.
duo_logo
Learn all about DUO here.

View or trade PAKX tokens.

@enginewitty, PAKX has voted the post by @paulmoon410. (1/1 calls)

Use !PAKX command if you hold enough balance to call for a @pakx vote on worthy posts! More details available on PAKX Blog.