fix: deep audit — numpy removal, OptimizedMixin wiring, strategy rewrite, example fixes#88
Merged
cleitonleonel merged 3 commits intocleitonleonel:masterfrom May 2, 2026
Conversation
…get_historical_candles and start_candles_one_stream --- open_pending while/else (closes cleitonleonel#83) --- The while/else construct caused instruments_follow() to fire on the failure path (loop condition False == pending_id never set) and be silently skipped on the success path. Replace with an explicit if-check after the loop so instruments_follow is called only when pending_id is actually present. --- sell_option race condition (closes cleitonleonel#84) --- sold_options_respond was reset to None AFTER the WebSocket request was sent. On fast connections the response can arrive before the reset, wiping the data and causing a guaranteed TimeoutError. Move the sentinel reset to before the send, consistent with how candles_data and other sentinels are handled in the codebase. --- get_historical_candles worker index collision (closes cleitonleonel#85) --- Each worker generated its request index as int(time.time() * 1000) + worker_id Two workers (or two iterations within the same worker) executing in the same millisecond produce identical indices. The event registry keys responses on this index, so workers steal each other's data silently. Replace with a module-level monotonic itertools.count seeded from the current millisecond so every request gets a globally unique index within the process. --- start_candles_one_stream follow_candle spam (closes cleitonleonel#86) --- follow_candle() (a WebSocket subscribe request) was called on every 0.2 s poll iteration, sending up to 100 subscribe messages per stream setup. Move the single subscribe call to before the loop; the loop body now only polls candle_generated_check and sleeps.
…te API reference
app.py — 27 commands now cover every public stable_api method:
Connection & Account (6)
login, balance, server-time, set-demo-balance, settings, test-all
Assets & Payouts (3)
assets, payout, payout-asset
Candle & Market Data (8)
candles, candles-v2, candles-deep, history-line, candle-info,
realtime-price, realtime-sentiment, realtime-candle
Trading (6)
buy, sell, pending, check, result, signals
History & Indicators (2)
history, indicator
Monitoring & Strategy (2)
monitor, strategy
New commands not previously in app.py:
server-time → get_server_time()
set-demo-balance → edit_practice_balance()
settings → store_settings_apply()
payout → get_payment()
payout-asset → get_payout_by_asset()
candles-v2 → get_candle_v2()
history-line → get_history_line()
candle-info → opening_closing_current_candle()
realtime-price → start_realtime_price() + get_realtime_price()
realtime-sentiment → start_realtime_sentiment() + get_realtime_sentiment()
realtime-candle → start_realtime_candle()
pending → open_pending()
result → get_result()
signals → start_signals_data() + get_signal_data()
indicator → calculate_indicator()
Other improvements:
- Shared _add_account_flags / _add_asset_flag parser helpers (DRY)
- _print_candles_table() shared table renderer for all candle commands
- _save_candles_csv() for candles-deep --output flag
- connect_with_retry() reused across all commands
- COMMAND_MAP dict dispatch (replaces if/elif chain)
- --demo/--live are now mutually exclusive groups
docs/en/API_REFERENCE.md — new complete API reference:
- All 52 public methods documented with signatures, params, return types
- CLI command table (27 commands)
- Error handling guide
- 8 complete usage examples (connect, RSI, trade+check, deep history,
live indicator, pending order, asset scan, CSV export)
…ite, example fixes --- refactor(indicators): remove numpy dependency (closes cleitonleonel#85-adjacent) --- All 7 numpy calls in calculate_rsi() and calculate_bollinger_bands() replaced with pure-Python / stdlib equivalents: np.diff() -> list comprehension np.where() -> list comprehension np.concatenate() -> list concatenation np.mean() -> sum()/len() np.std() -> statistics.pstdev() numpy (~20 MB) removed from pyproject.toml dependencies. Unblocks Termux/slim-image installs without any accuracy loss. --- fix(optimization): OptimizedQuotexMixin now wired into Quotex --- OptimizedQuotexMixin existed in utils/optimization.py but was never inherited by the Quotex class in stable_api.py, making all optimized methods (get_balance_optimized, get_instruments_optimized, buy_optimized, sell_option_optimized) completely unreachable. Fixed by: - Adding import in stable_api.py - Changing class Quotex: -> class Quotex(OptimizedQuotexMixin): --- fix(optimization): get_balance_optimized returned dict not float --- The fast-path branch returned self.api.account_balance raw (a dict), instead of extracting demoBalance/liveBalance like get_balance() does. Fixed to match exact extraction logic of the canonical get_balance(). --- fix(strategy): TripleConfirmationStrategy complete rewrite --- Original class had no client param, no async run(), and no candle fetching — it only had analyze() taking pre-fetched candles. app.py was calling TripleConfirmationStrategy(client, asset, period) which crashed immediately (wrong positional args). Rewritten with: - client, asset, period, amount as constructor params - async run(auto_trade, poll_interval) main loop - OTC asset fallback via get_available_asset(force_open=True) - Proper high/low key fallback (high|max, low|min) - asyncio.CancelledError + KeyboardInterrupt handling - stream cleanup in finally block --- fix(app): strategy command uses correct constructor call --- cmd_strategy was passing client as first positional arg then asset/period, which matched neither the old nor new signature. Updated to use keyword args. --- fix(examples/binary_bot): rewrite for async API --- Old binary_bot.py used the obsolete sync API (from pyquotex import Quotex, client.connect() sync, client.buy_simple(), client.get_open_trades()). Fully rewritten using stable_api.Quotex with: - async/await throughout - RSI + SMA pure-Python (no numpy) - check_win() task tracking for concurrent trades - credentials() config helper --- fix(examples/trade_by_signal): MA crossover logic was always 'buy' --- check_moving_average_cross() compared current short MA vs current long MA, which only shows current state, not a crossover. Fixed to compare current vs previous bar MAs so the function only fires on the actual cross event, not on every bar where short > long. --- fix(examples/wicks_quotex): buy() signature mismatch --- Called as buy(amount=, direction=, asset=, duration=) — wrong keyword names and wrong order. Fixed to positional: buy(amount, asset, direction, duration) matching the stable_api signature.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Deep audit of the full codebase identified 7 independent bugs/regressions. All fixed in this PR.
Changes
1.
refactor(indicators): remove numpy dependency — pure Python replacementProblem:
numpy(~20 MB) was listed as a required dependency but only 7 trivial calls existed inindicators.py— all incalculate_rsi()andcalculate_bollinger_bands(). Every other indicator (SMA, EMA, MACD, Stochastic, ATR, ADX, Ichimoku) was already pure Python. This blocked Termux/slim-image installs and was the reasonorjsonwas made optional.Fix: Replace all 7 numpy calls with stdlib equivalents (
statistics.pstdev, list comprehensions). Removenumpyfrompyproject.toml.2.
fix(stable_api):OptimizedQuotexMixinwas never wired intoQuotexProblem:
OptimizedQuotexMixininutils/optimization.pyprovidesget_balance_optimized(),get_instruments_optimized(),buy_optimized(), andsell_option_optimized()— butclass Quotex:never inherited it. All optimized methods were completely unreachable.Fix:
class Quotex(OptimizedQuotexMixin):+ import.3.
fix(optimization):get_balance_optimized()returned adictinstead offloatProblem: The fast-path branch returned
self.api.account_balanceraw — which is adictlike{"demoBalance": 1000, "liveBalance": 0}— instead of extracting the correct key likeget_balance()does.Fix: Mirror the exact
demoBalance/liveBalanceextraction logic ofget_balance().4.
fix(strategy):TripleConfirmationStrategycomplete rewriteProblem: The class had no
clientparam and norun()method.app.pywas callingTripleConfirmationStrategy(client, asset, period)— wrong positional args — which crashed immediately. Theanalyze()method also had a subtlehigh/lowkey bug (candles usemax/minin some paths).Fix: Rewrite with correct
__init__(client, asset, period, amount, ...)signature,async run(auto_trade, poll_interval)loop, OTC fallback, proper key handling, and stream cleanup.5.
fix(app):cmd_strategyused wrong constructor callProblem: Passed positional args that matched neither the old nor new strategy signature.
Fix: Use explicit keyword args matching the new constructor.
6.
fix(examples/binary_bot): rewrite for current async APIProblem: Used the obsolete sync API (
from pyquotex import Quotex, syncconnect(),buy_simple(),get_open_trades()) — none of which exist in the current codebase.Fix: Full async rewrite using
stable_api.Quotex, pure-Python RSI/SMA,check_win()task tracking.7.
fix(examples): two example bugstrade_by_signal.py:check_moving_average_cross()compared current MAs only — it returned the same direction on every bar where short > long, not just on the actual crossover. Fixed with previous-bar comparison.wicks_quotex.py:buy()called with wrong keyword names and order. Fixed to positional:buy(amount, asset, direction, duration).Files changed
pyproject.tomlnumpydependencypyquotex/utils/indicators.pypyquotex/stable_api.pyOptimizedQuotexMixinpyquotex/utils/optimization.pyget_balance_optimizedreturn typepyquotex/utils/strategy.pyclient+async run()app.pycmd_strategyconstructor callexamples/binary_bot.pyexamples/trade_by_signal.pyexamples/wicks_quotex.pybuy()signatureImpact / Risks
OptimizedQuotexMixininheritance adds new methods; existing methods unchanged