Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
144 changes: 144 additions & 0 deletions async_place_demo_order.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
#!/usr/bin/env python3
"""
async_place_demo_order.py
Usage:
source .venv/bin/activate
python async_place_demo_order.py
This script:
- Loads SSID from .env
- Connects with AsyncPocketOptionClient
- Attempts to place a small demo order using several common call signatures
- Prints responses and checks active orders
"""
import os
import asyncio
from dotenv import load_dotenv

load_dotenv()

SSID = os.getenv("SSID")
if not SSID:
raise SystemExit("SSID not found in .env. Add SSID=... (demo SSID, isDemo:1).")

try:
from pocketoptionapi_async.client import AsyncPocketOptionClient
except Exception as e:
raise SystemExit("Cannot import AsyncPocketOptionClient: " + str(e))
Comment on lines +24 to +27

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Catching the generic Exception is too broad and can hide other unexpected errors during startup. It's better to catch the specific ImportError that you're expecting here.

Suggested change
try:
from pocketoptionapi_async.client import AsyncPocketOptionClient
except Exception as e:
raise SystemExit("Cannot import AsyncPocketOptionClient: " + str(e))
try:
from pocketoptionapi_async.client import AsyncPocketOptionClient
except ImportError as e:
raise SystemExit("Cannot import AsyncPocketOptionClient: " + str(e))


# Configure order params (change asset/duration/amount to what your demo account supports)
AMOUNT = 1.0
ASSET = "EURUSD" # update if needed (use an asset visible in demo UI)
DIRECTION = "call" # or "put"
DURATION = 60 # seconds or API-specific timeframe

async def try_call(fn, *args, **kwargs):
try:
res = await fn(*args, **kwargs)
return True, res
except TypeError as te:
# signature mismatch
return False, te
except Exception as e:
return False, e

async def main():
client = AsyncPocketOptionClient(SSID)

print("Connecting...")
try:
await client.connect()
except Exception as e:
print("Failed to connect:", e)
return

print("Connected. Attempting to place order...")

# candidate method names in priority order
candidate_methods = [
"place_order",
"buy",
"create_order",
"trade",
"_send_order" # internal but present in some versions
]

tried = False
for method_name in candidate_methods:
if hasattr(client, method_name):
tried = True
method = getattr(client, method_name)
print(f"Trying method: {method_name} (positional)")

ok, res = await try_call(method, AMOUNT, ASSET, DURATION, DIRECTION)
if ok:
print(f"Success (positional) with {method_name} ->", res)
order_result = res
break

# try common keyword variations
kw_variants = [
{"amount": AMOUNT, "asset": ASSET, "direction": DIRECTION, "duration": DURATION},
{"amount": AMOUNT, "instrument": ASSET, "direction": DIRECTION, "duration": DURATION},
{"amount": AMOUNT, "asset": ASSET, "type": "binary", "duration": DURATION, "direction": DIRECTION},
{"value": AMOUNT, "asset": ASSET, "side": DIRECTION, "duration": DURATION},
]
for kw in kw_variants:
print(f"Trying {method_name} with kwargs: {list(kw.keys())}")
ok, res = await try_call(method, **kw)
if ok:
print(f"Success (kw) with {method_name} ->", res)
order_result = res
break
else:
print(f"{method_name} didn't accept attempted signatures; last error:", res)
order_result = None

if order_result is not None:
break

if not tried:
print("No candidate order methods found on client.")
else:
# If we got an order result, attempt to check order status / active orders
try:
if hasattr(client, "check_order_result"):
print("Calling check_order_result(...) to verify...")
try:
ok, info = await try_call(client.check_order_result, order_result)
print("check_order_result:", ok, info)
except Exception as e:
print("check_order_result call failed:", e)

if hasattr(client, "get_active_orders"):
print("Fetching active orders...")
ok, active = await try_call(client.get_active_orders)
if ok:
print("Active orders:", active)
else:
print("get_active_orders error:", active)
except Exception as e:
print("Post-order checks failed:", e)

# read balance if method exists
try:
if hasattr(client, "get_balance"):
bal = await client.get_balance()
print("Balance:", bal)
except Exception as e:
print("get_balance failed:", e)

# disconnect
try:
await client.disconnect()
except Exception:
# some forks use close/disconnect variations
try:
await client.close()
except Exception:
pass

print("Done.")
Comment on lines +45 to +141

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

The main function has a couple of issues:

  1. Resource Leak: It doesn't guarantee that client.disconnect() is called if an error occurs, which can lead to resource leaks. This is best fixed with a try...finally block.
  2. Logic Bug: If no order placement succeeds, order_result can be None and is then used in post-order checks, which can cause an error. This can be fixed by checking if order_result has a value before using it.

The suggested change refactors the function to address both issues for more robust and reliable execution.

async def main():
    client = AsyncPocketOptionClient(SSID)
    order_result = None
    try:
        print("Connecting...")
        try:
            await client.connect()
        except Exception as e:
            print("Failed to connect:", e)
            return

        print("Connected. Attempting to place order...")

        # candidate method names in priority order
        candidate_methods = [
            "place_order",
            "buy",
            "create_order",
            "trade",
            "_send_order"   # internal but present in some versions
        ]

        tried = False
        for method_name in candidate_methods:
            if hasattr(client, method_name):
                tried = True
                method = getattr(client, method_name)
                print(f"Trying method: {method_name} (positional)")

                ok, res = await try_call(method, AMOUNT, ASSET, DURATION, DIRECTION)
                if ok:
                    print(f"Success (positional) with {method_name} ->", res)
                    order_result = res
                    break

                # try common keyword variations
                kw_variants = [
                    {"amount": AMOUNT, "asset": ASSET, "direction": DIRECTION, "duration": DURATION},
                    {"amount": AMOUNT, "instrument": ASSET, "direction": DIRECTION, "duration": DURATION},
                    {"amount": AMOUNT, "asset": ASSET, "type": "binary", "duration": DURATION, "direction": DIRECTION},
                    {"value": AMOUNT, "asset": ASSET, "side": DIRECTION, "duration": DURATION},
                ]
                for kw in kw_variants:
                    print(f"Trying {method_name} with kwargs: {list(kw.keys())}")
                    ok, res = await try_call(method, **kw)
                    if ok:
                        print(f"Success (kw) with {method_name} ->", res)
                        order_result = res
                        break
                else:
                    print(f"{method_name} didn't accept attempted signatures; last error:", res)

                if order_result is not None:
                    break

        if not tried:
            print("No candidate order methods found on client.")
        elif order_result:
            # If we got an order result, attempt to check order status / active orders
            try:
                if hasattr(client, "check_order_result"):
                    print("Calling check_order_result(...) to verify...")
                    try:
                        ok, info = await try_call(client.check_order_result, order_result)
                        print("check_order_result:", ok, info)
                    except Exception as e:
                        print("check_order_result call failed:", e)

                if hasattr(client, "get_active_orders"):
                    print("Fetching active orders...")
                    ok, active = await try_call(client.get_active_orders)
                    if ok:
                        print("Active orders:", active)
                    else:
                        print("get_active_orders error:", active)
            except Exception as e:
                print("Post-order checks failed:", e)

        # read balance if method exists
        try:
            if hasattr(client, "get_balance"):
                bal = await client.get_balance()
                print("Balance:", bal)
        except Exception as e:
            print("get_balance failed:", e)

    finally:
        # disconnect
        if client:
            try:
                await client.disconnect()
            except Exception:
                # some forks use close/disconnect variations
                try:
                    await client.close()
                except Exception:
                    pass

        print("Done.")


if __name__ == "__main__":
asyncio.run(main())
78 changes: 78 additions & 0 deletions fix_imports.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
#!/usr/bin/env python3
"""
fix_imports.py
Usage:
python fix_imports.py /path/to/pocketoptionapi_async
Patches bare internal imports (e.g. `from models import X` or `import client`)
to package-qualified imports `from pocketoptionapi_async.models import X`
or `from pocketoptionapi_async import client`.
It will back up each file to filename.bak before editing.
"""
import sys, os, re, shutil

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

According to PEP 8, imports should be on separate lines. This improves readability.

import sys
import os
import re
import shutil


if len(sys.argv) < 2:
print("Usage: python fix_imports.py /path/to/pocketoptionapi_async")
sys.exit(1)

pkg_dir = sys.argv[1]
if not os.path.isdir(pkg_dir):
print("Directory not found:", pkg_dir)
sys.exit(2)

# determine candidate module names in that folder (module.py or package dir)
candidates = set()
for name in os.listdir(pkg_dir):
if name.endswith(".py"):
candidates.add(name[:-3])
elif os.path.isdir(os.path.join(pkg_dir, name)) and os.path.isfile(os.path.join(pkg_dir, name, "__init__.py")):
candidates.add(name)

print("Found candidate internal modules:", sorted(candidates))

# regex helpers
def replace_in_text(text, mod):
# 1) from <mod> import ...
pattern1 = re.compile(rf'(^|\n)(\s*)from\s+{re.escape(mod)}\s+import\s+', flags=re.MULTILINE)
repl1 = rf'\1\2from pocketoptionapi_async.{mod} import '
text = pattern1.sub(repl1, text)

# 2) import <mod> [as ...] -> convert to `from pocketoptionapi_async import <mod> [as ...]`
# but avoid converting "import a, b" or "import pkg.mod"
pattern2 = re.compile(rf'(^|\n)(\s*)import\s+{re.escape(mod)}(\s|$|,| as)', flags=re.MULTILINE)
repl2 = rf'\1\2from pocketoptionapi_async import {mod}\3'
text = pattern2.sub(repl2, text)

return text

# walk and patch
patched_files = []
for root, _, files in os.walk(pkg_dir):
for fname in files:
if not fname.endswith(".py"):
continue
path = os.path.join(root, fname)
with open(path, "r", encoding="utf-8") as f:
text = f.read()
new_text = text
for mod in sorted(candidates, key=lambda x: -len(x)): # longer first
# avoid changing the very file which defines the module if it imports itself
# but it's safe to replace in general
new_text = replace_in_text(new_text, mod)

if new_text != text:
bak = path + ".bak"
print("Patching", path, "-> backup saved to", bak)
shutil.copy2(path, bak)
with open(path, "w", encoding="utf-8") as f:
f.write(new_text)
patched_files.append(path)

if not patched_files:
print("No files required patching.")
else:
print("Patched files count:", len(patched_files))
for p in patched_files:
print(" -", p)
print("Done.")
47 changes: 47 additions & 0 deletions inspect_pocket.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
# inspect_pocket.py
import importlib, pkgutil, inspect, os

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

According to PEP 8, imports should be on separate lines for better readability.

Suggested change
import importlib, pkgutil, inspect, os
import importlib
import pkgutil
import inspect
import os

import sys

# make sure repo root is importable
root = os.path.abspath(os.path.dirname(__file__))
if root not in sys.path:
sys.path.insert(0, root)

PKG = "pocketoptionapi_async"

try:
pkg = importlib.import_module(PKG)
except Exception as e:
print("Failed to import package", PKG, ":", e)
sys.exit(1)

print("Package imported:", pkg)
print("\nTop-level modules in package:")
for m in pkgutil.iter_modules(pkg.__path__):
print(" -", m.name)

candidates = []
print("\nScanning modules for classes and order-like methods (this may take a sec)...\n")
for finder, name, ispkg in pkgutil.walk_packages(pkg.__path__, pkg.__name__ + "."):
try:
mod = importlib.import_module(name)
except Exception as e:
print(" (skip) failed to import", name, ":", e)
continue
for cls_name, cls in inspect.getmembers(mod, inspect.isclass):
# only show classes defined in this package
if cls.__module__.startswith(PKG):
methods = [m for m, _ in inspect.getmembers(cls, inspect.isfunction)]
# look for order-like methods
order_like = [m for m in methods if any(x in m.lower() for x in ("buy", "place", "order", "trade", "create"))]
if order_like:
print(f"Class: {cls.__module__}.{cls_name}")
print(" order-like methods:", order_like)
candidates.append((cls.__module__, cls_name, order_like))
else:
# also show client-ish classes
if any(x in cls_name.lower() for x in ("client","pocket","async")):
print(f"Class: {cls.__module__}.{cls_name}")
print(" methods sample:", methods[:8])
# small separator
print("\nDone. If nothing useful shows up paste the output here and I’ll produce the exact script.")
65 changes: 65 additions & 0 deletions place_demo_order.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
#!/usr/bin/env python3
import os
from dotenv import load_dotenv
load_dotenv()

# Try common import; adapt if your repo uses different module names
try:
# common sync API wrapper
from pocketoptionapi_async.stable_api import PocketOption
except Exception:
Comment on lines +7 to +10

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Catching a generic Exception is too broad and can hide unexpected errors. It's better to catch the specific ImportError you're expecting.

Suggested change
try:
# common sync API wrapper
from pocketoptionapi_async.stable_api import PocketOption
except Exception:
try:
# common sync API wrapper
from pocketoptionapi_async.stable_api import PocketOption
except ImportError:

# fallback to client (some forks expose sync client differently)
try:
from pocketoptionapi_async.client import PocketOption as PocketOption

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The alias as PocketOption is redundant here, as you are importing a name and aliasing it to the same name. You can remove the alias for cleaner code.

Suggested change
from pocketoptionapi_async.client import PocketOption as PocketOption
from pocketoptionapi_async.client import PocketOption

except Exception:
raise SystemExit("Cannot import PocketOption class. Run grep as explained in README to find the class name.")

def main():
ssid = os.getenv("SSID")
if not ssid:
raise SystemExit("SSID not set. Put it in .env or export SSID in shell.")

api = PocketOption(ssid) # instantiate client
ok, msg = api.connect() # many forks return (ok, msg) from connect
if not ok:
print("Connect failed:", msg)
return

# --- change these to an asset available in demo account ---
amount = 1.0
asset = "EURUSD" # example — use an asset listed by the demo account
direction = "call" # or "put"
duration = 60 # seconds or API-specific timeframe

# Try common method names in order of likelihood
for method in ("buy", "place_order", "create_order", "trade"):
if hasattr(api, method):
fn = getattr(api, method)
try:
print(f"Using method: {method}")
res = fn(amount, asset, duration, direction) # many libs use this signature
except TypeError:
# try keyword style
try:
res = fn(amount=amount, asset=asset, direction=direction, duration=duration)
except Exception as e:
print("Method exists but calling failed:", e)
res = None
print("Result:", res)
break
else:
print("No typical order method found on api object. See instructions to grep for available methods.")

try:
# read balance or open positions if available
if hasattr(api, "get_balance"):
print("Balance:", api.get_balance())
elif hasattr(api, "balance"):
print("Balance property:", api.balance)
except Exception:
pass

api.close()
Comment on lines +17 to +62

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

The main function has two issues:

  1. Resource Leak: api.close() is not guaranteed to be called on an error, which can lead to resource leaks. A try...finally block is needed.
  2. Logic Bug: The loop to find an order method has a break that causes it to exit after the first attempt, whether it was successful or not. It should only break on success.

The suggested refactoring addresses both points for a more robust script.

def main():
    ssid = os.getenv("SSID")
    if not ssid:
        raise SystemExit("SSID not set. Put it in .env or export SSID in shell.")

    api = PocketOption(ssid)            # instantiate client
    try:
        ok, msg = api.connect()             # many forks return (ok, msg) from connect
        if not ok:
            print("Connect failed:", msg)
            return

        # --- change these to an asset available in demo account ---
        amount = 1.0
        asset = "EURUSD"      # example — use an asset listed by the demo account
        direction = "call"    # or "put"
        duration = 60         # seconds or API-specific timeframe

        # Try common method names in order of likelihood
        order_successful = False
        for method in ("buy", "place_order", "create_order", "trade"):
            if hasattr(api, method):
                fn = getattr(api, method)
                try:
                    print(f"Using method: {method} (positional)")
                    res = fn(amount, asset, duration, direction)  # many libs use this signature
                    print("Result:", res)
                    order_successful = True
                    break # Success, so exit loop
                except TypeError:
                    # try keyword style
                    try:
                        print(f"Using method: {method} (keyword)")
                        res = fn(amount=amount, asset=asset, direction=direction, duration=duration)
                        print("Result:", res)
                        order_successful = True
                        break # Success, so exit loop
                    except Exception as e:
                        print(f"Method '{method}' with kwargs failed: {e}")
                except Exception as e:
                    print(f"Method '{method}' failed: {e}")
        
        if not order_successful:
            print("No typical order method found on api object, or all attempts failed.")

        try:
            # read balance or open positions if available
            if hasattr(api, "get_balance"):
                print("Balance:", api.get_balance())
            elif hasattr(api, "balance"):
                print("Balance property:", api.balance)
        except Exception:
            pass
    finally:
        api.close()


if __name__ == "__main__":
main()
7 changes: 5 additions & 2 deletions pocketoptionapi_async/connection_keep_alive.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,11 @@
from websockets.exceptions import ConnectionClosed
from websockets.legacy.client import connect, WebSocketClientProtocol

from models import ConnectionInfo, ConnectionStatus
from constants import REGIONS
#from models import ConnectionInfo, ConnectionStatus
from pocketoptionapi_async.models import ConnectionInfo, ConnectionStatus
from pocketoptionapi_async.constants import REGIONS

#from constants import REGIONS


class ConnectionKeepAlive:
Expand Down
2 changes: 1 addition & 1 deletion pocketoptionapi_async/connection_monitor.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
import statistics
from loguru import logger

from client import AsyncPocketOptionClient
from pocketoptionapi_async.client import AsyncPocketOptionClient


@dataclass
Expand Down
Loading