BinaryOptionsToolsV2 0.2.12__tar.gz → 0.2.13__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of BinaryOptionsToolsV2 might be problematic. Click here for more details.

Files changed (132) hide show
  1. {binaryoptionstoolsv2-0.2.12 → binaryoptionstoolsv2-0.2.13}/BinaryOptionsToolsV2/config.py +12 -5
  2. {binaryoptionstoolsv2-0.2.12 → binaryoptionstoolsv2-0.2.13}/BinaryOptionsToolsV2/pocketoption/asynchronous.py +259 -21
  3. {binaryoptionstoolsv2-0.2.12 → binaryoptionstoolsv2-0.2.13}/BinaryOptionsToolsV2/pocketoption/synchronous.py +131 -21
  4. {binaryoptionstoolsv2-0.2.12 → binaryoptionstoolsv2-0.2.13}/Cargo.lock +247 -229
  5. {binaryoptionstoolsv2-0.2.12 → binaryoptionstoolsv2-0.2.13}/Cargo.toml +2 -2
  6. {binaryoptionstoolsv2-0.2.12 → binaryoptionstoolsv2-0.2.13}/LICENSE +2 -2
  7. {binaryoptionstoolsv2-0.2.12 → binaryoptionstoolsv2-0.2.13}/PKG-INFO +34 -40
  8. {binaryoptionstoolsv2-0.2.12 → binaryoptionstoolsv2-0.2.13}/README.md +26 -33
  9. {binaryoptionstoolsv2-0.2.12 → binaryoptionstoolsv2-0.2.13}/crates/binary_options_tools/Cargo.toml +8 -6
  10. {binaryoptionstoolsv2-0.2.12/crates/macros → binaryoptionstoolsv2-0.2.13/crates/binary_options_tools}/LICENSE +2 -2
  11. {binaryoptionstoolsv2-0.2.12 → binaryoptionstoolsv2-0.2.13}/crates/binary_options_tools/Readme.md +1 -1
  12. {binaryoptionstoolsv2-0.2.12 → binaryoptionstoolsv2-0.2.13}/crates/binary_options_tools/src/config.rs +13 -6
  13. {binaryoptionstoolsv2-0.2.12 → binaryoptionstoolsv2-0.2.13}/crates/binary_options_tools/src/expertoptions/modules/profile.rs +5 -3
  14. {binaryoptionstoolsv2-0.2.12 → binaryoptionstoolsv2-0.2.13}/crates/binary_options_tools/src/expertoptions/types.rs +1 -1
  15. {binaryoptionstoolsv2-0.2.12 → binaryoptionstoolsv2-0.2.13}/crates/binary_options_tools/src/pocketoption/candle.rs +1 -1
  16. {binaryoptionstoolsv2-0.2.12 → binaryoptionstoolsv2-0.2.13}/crates/binary_options_tools/src/pocketoption/connect.rs +10 -8
  17. {binaryoptionstoolsv2-0.2.12 → binaryoptionstoolsv2-0.2.13}/crates/binary_options_tools/src/pocketoption/modules/deals.rs +3 -1
  18. {binaryoptionstoolsv2-0.2.12 → binaryoptionstoolsv2-0.2.13}/crates/binary_options_tools/src/pocketoption/modules/get_candles.rs +34 -3
  19. {binaryoptionstoolsv2-0.2.12 → binaryoptionstoolsv2-0.2.13}/crates/binary_options_tools/src/pocketoption/modules/historical_data.rs +12 -4
  20. {binaryoptionstoolsv2-0.2.12 → binaryoptionstoolsv2-0.2.13}/crates/binary_options_tools/src/pocketoption/modules/keep_alive.rs +2 -6
  21. {binaryoptionstoolsv2-0.2.12 → binaryoptionstoolsv2-0.2.13}/crates/binary_options_tools/src/pocketoption/modules/pending_trades_tests.rs +7 -1
  22. {binaryoptionstoolsv2-0.2.12 → binaryoptionstoolsv2-0.2.13}/crates/binary_options_tools/src/pocketoption/modules/subscriptions.rs +1 -28
  23. {binaryoptionstoolsv2-0.2.12 → binaryoptionstoolsv2-0.2.13}/crates/binary_options_tools/src/pocketoption/pocket_client.rs +46 -8
  24. {binaryoptionstoolsv2-0.2.12 → binaryoptionstoolsv2-0.2.13}/crates/binary_options_tools/src/pocketoption/state.rs +55 -11
  25. {binaryoptionstoolsv2-0.2.12 → binaryoptionstoolsv2-0.2.13}/crates/binary_options_tools/src/pocketoption/utils.rs +342 -41
  26. {binaryoptionstoolsv2-0.2.12 → binaryoptionstoolsv2-0.2.13}/crates/bindings_pyo3/Cargo.toml +6 -6
  27. {binaryoptionstoolsv2-0.2.12/crates/binary_options_tools → binaryoptionstoolsv2-0.2.13/crates/bindings_pyo3}/LICENSE +2 -2
  28. {binaryoptionstoolsv2-0.2.12 → binaryoptionstoolsv2-0.2.13}/crates/bindings_pyo3/Readme.md +20 -34
  29. {binaryoptionstoolsv2-0.2.12 → binaryoptionstoolsv2-0.2.13}/crates/bindings_pyo3/build.rs +11 -1
  30. {binaryoptionstoolsv2-0.2.12 → binaryoptionstoolsv2-0.2.13}/crates/bindings_pyo3/src/config.rs +55 -4
  31. {binaryoptionstoolsv2-0.2.12 → binaryoptionstoolsv2-0.2.13}/crates/bindings_pyo3/src/pocketoption.rs +33 -4
  32. {binaryoptionstoolsv2-0.2.12 → binaryoptionstoolsv2-0.2.13}/crates/core/Cargo.toml +5 -5
  33. {binaryoptionstoolsv2-0.2.12 → binaryoptionstoolsv2-0.2.13}/crates/core/LICENSE +2 -2
  34. {binaryoptionstoolsv2-0.2.12 → binaryoptionstoolsv2-0.2.13}/crates/core/macros/Cargo.toml +2 -2
  35. {binaryoptionstoolsv2-0.2.12 → binaryoptionstoolsv2-0.2.13}/crates/core/macros/LICENSE +2 -2
  36. {binaryoptionstoolsv2-0.2.12 → binaryoptionstoolsv2-0.2.13}/crates/core/src/client.rs +5 -2
  37. {binaryoptionstoolsv2-0.2.12 → binaryoptionstoolsv2-0.2.13}/crates/core/src/signals.rs +10 -6
  38. {binaryoptionstoolsv2-0.2.12 → binaryoptionstoolsv2-0.2.13}/crates/macros/Cargo.toml +4 -4
  39. {binaryoptionstoolsv2-0.2.12/crates/bindings_pyo3 → binaryoptionstoolsv2-0.2.13/crates/macros}/LICENSE +2 -2
  40. {binaryoptionstoolsv2-0.2.12 → binaryoptionstoolsv2-0.2.13}/pyproject.toml +7 -7
  41. {binaryoptionstoolsv2-0.2.12 → binaryoptionstoolsv2-0.2.13}/BinaryOptionsToolsV2/BinaryOptionsToolsV2.pyi +0 -0
  42. {binaryoptionstoolsv2-0.2.12 → binaryoptionstoolsv2-0.2.13}/BinaryOptionsToolsV2/__init__.py +0 -0
  43. {binaryoptionstoolsv2-0.2.12 → binaryoptionstoolsv2-0.2.13}/BinaryOptionsToolsV2/pocketoption/__init__.py +0 -0
  44. {binaryoptionstoolsv2-0.2.12 → binaryoptionstoolsv2-0.2.13}/BinaryOptionsToolsV2/pocketoption/tools/__init__.py +0 -0
  45. {binaryoptionstoolsv2-0.2.12 → binaryoptionstoolsv2-0.2.13}/BinaryOptionsToolsV2/pocketoption/tools/login.py +0 -0
  46. {binaryoptionstoolsv2-0.2.12 → binaryoptionstoolsv2-0.2.13}/BinaryOptionsToolsV2/tracing.py +0 -0
  47. {binaryoptionstoolsv2-0.2.12 → binaryoptionstoolsv2-0.2.13}/BinaryOptionsToolsV2/validator.py +0 -0
  48. {binaryoptionstoolsv2-0.2.12 → binaryoptionstoolsv2-0.2.13}/crates/binary_options_tools/data/expert_options_regions.json +0 -0
  49. {binaryoptionstoolsv2-0.2.12 → binaryoptionstoolsv2-0.2.13}/crates/binary_options_tools/data/pocket_options_regions.json +0 -0
  50. {binaryoptionstoolsv2-0.2.12 → binaryoptionstoolsv2-0.2.13}/crates/binary_options_tools/src/error.rs +0 -0
  51. {binaryoptionstoolsv2-0.2.12 → binaryoptionstoolsv2-0.2.13}/crates/binary_options_tools/src/expertoptions/action.rs +0 -0
  52. {binaryoptionstoolsv2-0.2.12 → binaryoptionstoolsv2-0.2.13}/crates/binary_options_tools/src/expertoptions/client.rs +0 -0
  53. {binaryoptionstoolsv2-0.2.12 → binaryoptionstoolsv2-0.2.13}/crates/binary_options_tools/src/expertoptions/connect.rs +0 -0
  54. {binaryoptionstoolsv2-0.2.12 → binaryoptionstoolsv2-0.2.13}/crates/binary_options_tools/src/expertoptions/error.rs +0 -0
  55. {binaryoptionstoolsv2-0.2.12 → binaryoptionstoolsv2-0.2.13}/crates/binary_options_tools/src/expertoptions/mod.rs +0 -0
  56. {binaryoptionstoolsv2-0.2.12 → binaryoptionstoolsv2-0.2.13}/crates/binary_options_tools/src/expertoptions/modules/keep_alive.rs +0 -0
  57. {binaryoptionstoolsv2-0.2.12 → binaryoptionstoolsv2-0.2.13}/crates/binary_options_tools/src/expertoptions/modules/mod.rs +0 -0
  58. {binaryoptionstoolsv2-0.2.12 → binaryoptionstoolsv2-0.2.13}/crates/binary_options_tools/src/expertoptions/regions.rs +0 -0
  59. {binaryoptionstoolsv2-0.2.12 → binaryoptionstoolsv2-0.2.13}/crates/binary_options_tools/src/expertoptions/state.rs +0 -0
  60. {binaryoptionstoolsv2-0.2.12 → binaryoptionstoolsv2-0.2.13}/crates/binary_options_tools/src/framework/market.rs +0 -0
  61. {binaryoptionstoolsv2-0.2.12 → binaryoptionstoolsv2-0.2.13}/crates/binary_options_tools/src/framework/mod.rs +0 -0
  62. {binaryoptionstoolsv2-0.2.12 → binaryoptionstoolsv2-0.2.13}/crates/binary_options_tools/src/framework/virtual_market.rs +0 -0
  63. {binaryoptionstoolsv2-0.2.12 → binaryoptionstoolsv2-0.2.13}/crates/binary_options_tools/src/lib.rs +0 -0
  64. {binaryoptionstoolsv2-0.2.12 → binaryoptionstoolsv2-0.2.13}/crates/binary_options_tools/src/pocketoption/error.rs +0 -0
  65. {binaryoptionstoolsv2-0.2.12 → binaryoptionstoolsv2-0.2.13}/crates/binary_options_tools/src/pocketoption/mod.rs +0 -0
  66. {binaryoptionstoolsv2-0.2.12 → binaryoptionstoolsv2-0.2.13}/crates/binary_options_tools/src/pocketoption/modules/assets.rs +0 -0
  67. {binaryoptionstoolsv2-0.2.12 → binaryoptionstoolsv2-0.2.13}/crates/binary_options_tools/src/pocketoption/modules/balance.rs +0 -0
  68. {binaryoptionstoolsv2-0.2.12 → binaryoptionstoolsv2-0.2.13}/crates/binary_options_tools/src/pocketoption/modules/deals_tests.rs +0 -0
  69. {binaryoptionstoolsv2-0.2.12 → binaryoptionstoolsv2-0.2.13}/crates/binary_options_tools/src/pocketoption/modules/mod.rs +0 -0
  70. {binaryoptionstoolsv2-0.2.12 → binaryoptionstoolsv2-0.2.13}/crates/binary_options_tools/src/pocketoption/modules/pending_trades.rs +0 -0
  71. {binaryoptionstoolsv2-0.2.12 → binaryoptionstoolsv2-0.2.13}/crates/binary_options_tools/src/pocketoption/modules/raw.rs +0 -0
  72. {binaryoptionstoolsv2-0.2.12 → binaryoptionstoolsv2-0.2.13}/crates/binary_options_tools/src/pocketoption/modules/resilient_parsing_tests.rs +0 -0
  73. {binaryoptionstoolsv2-0.2.12 → binaryoptionstoolsv2-0.2.13}/crates/binary_options_tools/src/pocketoption/modules/server_time.rs +0 -0
  74. {binaryoptionstoolsv2-0.2.12 → binaryoptionstoolsv2-0.2.13}/crates/binary_options_tools/src/pocketoption/modules/trades.rs +0 -0
  75. {binaryoptionstoolsv2-0.2.12 → binaryoptionstoolsv2-0.2.13}/crates/binary_options_tools/src/pocketoption/modules/trades_tests/common.rs +0 -0
  76. {binaryoptionstoolsv2-0.2.12 → binaryoptionstoolsv2-0.2.13}/crates/binary_options_tools/src/pocketoption/modules/trades_tests/concurrency.rs +0 -0
  77. {binaryoptionstoolsv2-0.2.12 → binaryoptionstoolsv2-0.2.13}/crates/binary_options_tools/src/pocketoption/modules/trades_tests/mod.rs +0 -0
  78. {binaryoptionstoolsv2-0.2.12 → binaryoptionstoolsv2-0.2.13}/crates/binary_options_tools/src/pocketoption/regions.rs +0 -0
  79. {binaryoptionstoolsv2-0.2.12 → binaryoptionstoolsv2-0.2.13}/crates/binary_options_tools/src/pocketoption/ssid.rs +0 -0
  80. {binaryoptionstoolsv2-0.2.12 → binaryoptionstoolsv2-0.2.13}/crates/binary_options_tools/src/pocketoption/types.rs +0 -0
  81. {binaryoptionstoolsv2-0.2.12 → binaryoptionstoolsv2-0.2.13}/crates/binary_options_tools/src/traits.rs +0 -0
  82. {binaryoptionstoolsv2-0.2.12 → binaryoptionstoolsv2-0.2.13}/crates/binary_options_tools/src/utils/mod.rs +0 -0
  83. {binaryoptionstoolsv2-0.2.12 → binaryoptionstoolsv2-0.2.13}/crates/binary_options_tools/src/utils/serialize.rs +0 -0
  84. {binaryoptionstoolsv2-0.2.12 → binaryoptionstoolsv2-0.2.13}/crates/binary_options_tools/src/validator.rs +0 -0
  85. {binaryoptionstoolsv2-0.2.12 → binaryoptionstoolsv2-0.2.13}/crates/bindings_pyo3/src/error.rs +0 -0
  86. {binaryoptionstoolsv2-0.2.12 → binaryoptionstoolsv2-0.2.13}/crates/bindings_pyo3/src/framework.rs +0 -0
  87. {binaryoptionstoolsv2-0.2.12 → binaryoptionstoolsv2-0.2.13}/crates/bindings_pyo3/src/lib.rs +0 -0
  88. {binaryoptionstoolsv2-0.2.12 → binaryoptionstoolsv2-0.2.13}/crates/bindings_pyo3/src/logs.rs +0 -0
  89. {binaryoptionstoolsv2-0.2.12 → binaryoptionstoolsv2-0.2.13}/crates/bindings_pyo3/src/runtime.rs +0 -0
  90. {binaryoptionstoolsv2-0.2.12 → binaryoptionstoolsv2-0.2.13}/crates/bindings_pyo3/src/stream.rs +0 -0
  91. {binaryoptionstoolsv2-0.2.12 → binaryoptionstoolsv2-0.2.13}/crates/bindings_pyo3/src/validator.rs +0 -0
  92. {binaryoptionstoolsv2-0.2.12 → binaryoptionstoolsv2-0.2.13}/crates/core/.gitignore +0 -0
  93. {binaryoptionstoolsv2-0.2.12 → binaryoptionstoolsv2-0.2.13}/crates/core/README.md +0 -0
  94. {binaryoptionstoolsv2-0.2.12 → binaryoptionstoolsv2-0.2.13}/crates/core/diagrams/architecture.txt +0 -0
  95. {binaryoptionstoolsv2-0.2.12 → binaryoptionstoolsv2-0.2.13}/crates/core/diagrams/diagram.txt +0 -0
  96. {binaryoptionstoolsv2-0.2.12 → binaryoptionstoolsv2-0.2.13}/crates/core/docs/testing-framework.md +0 -0
  97. {binaryoptionstoolsv2-0.2.12 → binaryoptionstoolsv2-0.2.13}/crates/core/examples/echo_client.rs +0 -0
  98. {binaryoptionstoolsv2-0.2.12 → binaryoptionstoolsv2-0.2.13}/crates/core/examples/middleware_example.rs +0 -0
  99. {binaryoptionstoolsv2-0.2.12 → binaryoptionstoolsv2-0.2.13}/crates/core/examples/testing_echo_client.rs +0 -0
  100. {binaryoptionstoolsv2-0.2.12 → binaryoptionstoolsv2-0.2.13}/crates/core/macros/src/lib.rs +0 -0
  101. {binaryoptionstoolsv2-0.2.12 → binaryoptionstoolsv2-0.2.13}/crates/core/macros/src/modules/lightweight.rs +0 -0
  102. {binaryoptionstoolsv2-0.2.12 → binaryoptionstoolsv2-0.2.13}/crates/core/macros/src/modules/mod.rs +0 -0
  103. {binaryoptionstoolsv2-0.2.12 → binaryoptionstoolsv2-0.2.13}/crates/core/macros/src/rule.rs +0 -0
  104. {binaryoptionstoolsv2-0.2.12 → binaryoptionstoolsv2-0.2.13}/crates/core/src/builder.rs +0 -0
  105. {binaryoptionstoolsv2-0.2.12 → binaryoptionstoolsv2-0.2.13}/crates/core/src/callback.rs +0 -0
  106. {binaryoptionstoolsv2-0.2.12 → binaryoptionstoolsv2-0.2.13}/crates/core/src/connector.rs +0 -0
  107. {binaryoptionstoolsv2-0.2.12 → binaryoptionstoolsv2-0.2.13}/crates/core/src/error.rs +0 -0
  108. {binaryoptionstoolsv2-0.2.12 → binaryoptionstoolsv2-0.2.13}/crates/core/src/lib.rs +0 -0
  109. {binaryoptionstoolsv2-0.2.12 → binaryoptionstoolsv2-0.2.13}/crates/core/src/message.rs +0 -0
  110. {binaryoptionstoolsv2-0.2.12 → binaryoptionstoolsv2-0.2.13}/crates/core/src/middleware.rs +0 -0
  111. {binaryoptionstoolsv2-0.2.12 → binaryoptionstoolsv2-0.2.13}/crates/core/src/reimports.rs +0 -0
  112. {binaryoptionstoolsv2-0.2.12 → binaryoptionstoolsv2-0.2.13}/crates/core/src/rules.rs +0 -0
  113. {binaryoptionstoolsv2-0.2.12 → binaryoptionstoolsv2-0.2.13}/crates/core/src/statistics.rs +0 -0
  114. {binaryoptionstoolsv2-0.2.12 → binaryoptionstoolsv2-0.2.13}/crates/core/src/testing.rs +0 -0
  115. {binaryoptionstoolsv2-0.2.12 → binaryoptionstoolsv2-0.2.13}/crates/core/src/traits.rs +0 -0
  116. {binaryoptionstoolsv2-0.2.12 → binaryoptionstoolsv2-0.2.13}/crates/core/src/utils/mod.rs +0 -0
  117. {binaryoptionstoolsv2-0.2.12 → binaryoptionstoolsv2-0.2.13}/crates/core/src/utils/stream.rs +0 -0
  118. {binaryoptionstoolsv2-0.2.12 → binaryoptionstoolsv2-0.2.13}/crates/core/src/utils/time.rs +0 -0
  119. {binaryoptionstoolsv2-0.2.12 → binaryoptionstoolsv2-0.2.13}/crates/core/src/utils/tracing.rs +0 -0
  120. {binaryoptionstoolsv2-0.2.12 → binaryoptionstoolsv2-0.2.13}/crates/core/tests/middleware_tests.rs +0 -0
  121. {binaryoptionstoolsv2-0.2.12 → binaryoptionstoolsv2-0.2.13}/crates/core/tests/rule_macro_tests.rs +0 -0
  122. {binaryoptionstoolsv2-0.2.12 → binaryoptionstoolsv2-0.2.13}/crates/core/tests/runner_command_tests.rs +0 -0
  123. {binaryoptionstoolsv2-0.2.12 → binaryoptionstoolsv2-0.2.13}/crates/core/tests/stream_tests.rs +0 -0
  124. {binaryoptionstoolsv2-0.2.12 → binaryoptionstoolsv2-0.2.13}/crates/core/tests/testing_wrapper_tests.rs +0 -0
  125. {binaryoptionstoolsv2-0.2.12 → binaryoptionstoolsv2-0.2.13}/crates/core/tests/two_step_standalone.rs +0 -0
  126. {binaryoptionstoolsv2-0.2.12 → binaryoptionstoolsv2-0.2.13}/crates/macros/.gitignore +0 -0
  127. {binaryoptionstoolsv2-0.2.12 → binaryoptionstoolsv2-0.2.13}/crates/macros/ActionImpl_README.md +0 -0
  128. {binaryoptionstoolsv2-0.2.12 → binaryoptionstoolsv2-0.2.13}/crates/macros/Cargo.lock +0 -0
  129. {binaryoptionstoolsv2-0.2.12 → binaryoptionstoolsv2-0.2.13}/crates/macros/src/action.rs +0 -0
  130. {binaryoptionstoolsv2-0.2.12 → binaryoptionstoolsv2-0.2.13}/crates/macros/src/lib.rs +0 -0
  131. {binaryoptionstoolsv2-0.2.12 → binaryoptionstoolsv2-0.2.13}/crates/macros/src/region.rs +0 -0
  132. {binaryoptionstoolsv2-0.2.12 → binaryoptionstoolsv2-0.2.13}/crates/macros/src/timeout.rs +0 -0
@@ -27,7 +27,12 @@ class Config:
27
27
  connection_initialization_timeout_secs: int = 60
28
28
  timeout_secs: int = 30
29
29
  urls: List[str] = field(default_factory=list)
30
- max_subscriptions: int = 4
30
+ proxy: str = None
31
+ user_agent: str = None
32
+ origin: str = None
33
+ sec_websocket_extensions: str = None
34
+ tls_cipher_suites: List[str] = None
35
+ tls_alpn: List[str] = None
31
36
 
32
37
  # Logging configuration
33
38
  terminal_logging: bool = False
@@ -67,7 +72,12 @@ class Config:
67
72
  self._pyconfig.connection_initialization_timeout_secs = self.connection_initialization_timeout_secs
68
73
  self._pyconfig.timeout_secs = self.timeout_secs
69
74
  self._pyconfig.urls = self.urls
70
- self._pyconfig.max_subscriptions = self.max_subscriptions
75
+ self._pyconfig.proxy = self.proxy
76
+ self._pyconfig.user_agent = self.user_agent
77
+ self._pyconfig.origin = self.origin
78
+ self._pyconfig.sec_websocket_extensions = self.sec_websocket_extensions
79
+ self._pyconfig.tls_cipher_suites = self.tls_cipher_suites
80
+ self._pyconfig.tls_alpn = self.tls_alpn
71
81
 
72
82
  def _validate(self):
73
83
  """Validate config values, raising ValueError on invalid input."""
@@ -81,8 +91,6 @@ class Config:
81
91
  raise ValueError("connection_initialization_timeout_secs must be at least 1")
82
92
  if self.timeout_secs < 1:
83
93
  raise ValueError("timeout_secs must be at least 1")
84
- if self.max_subscriptions < 1:
85
- raise ValueError("max_subscriptions must be at least 1")
86
94
 
87
95
  @classmethod
88
96
  def from_dict(cls, config_dict: Dict[str, Any]) -> "Config":
@@ -105,7 +113,6 @@ class Config:
105
113
  "connection_initialization_timeout_secs": self.connection_initialization_timeout_secs,
106
114
  "timeout_secs": self.timeout_secs,
107
115
  "urls": self.urls,
108
- "max_subscriptions": self.max_subscriptions,
109
116
  "terminal_logging": self.terminal_logging,
110
117
  "log_level": self.log_level,
111
118
  "extra_duration": self.extra_duration,
@@ -2,8 +2,11 @@ import asyncio
2
2
  import json
3
3
  import re
4
4
  import sys
5
- from datetime import timedelta
6
- from typing import TYPE_CHECKING, Dict, List, Optional, Tuple, Union
5
+ import time
6
+ import warnings
7
+ from collections import deque
8
+ from datetime import datetime, timezone, timedelta
9
+ from typing import TYPE_CHECKING, Dict, List, Optional, Tuple, Union, AsyncGenerator
7
10
 
8
11
  from ..config import Config
9
12
  from ..validator import Validator
@@ -30,6 +33,18 @@ class AsyncSubscription:
30
33
  return json.loads(await anext(self.subscription))
31
34
 
32
35
 
36
+ class AsyncRawSubscription:
37
+ def __init__(self, subscription):
38
+ """Asynchronous Iterator over raw message strings"""
39
+ self.subscription = subscription
40
+
41
+ def __aiter__(self):
42
+ return self
43
+
44
+ async def __anext__(self):
45
+ return await anext(self.subscription)
46
+
47
+
33
48
  class RawHandler:
34
49
  """
35
50
  Handler for advanced raw WebSocket message operations.
@@ -453,9 +468,23 @@ class PocketOptionAsync:
453
468
  - high: Highest price
454
469
  - low: Lowest price
455
470
  - close: Closing price
456
- """
457
- candles = await self.client.candles(asset, period)
458
- return json.loads(candles)
471
+
472
+ Note:
473
+ WARNING: This function only fetches closed historical candles and is intended
474
+ for training models, backtesting, or historical analysis. It is NOT designed
475
+ for real-time/live trading as it does not include the current forming candle
476
+ and can introduce gaps if called sequentially during live trading.
477
+ For live gap-free candle feeds, use `get_candles_live()` instead.
478
+ """
479
+ warnings.warn(
480
+ "candles() is deprecated and will be removed in a new release. "
481
+ "Please use get_candles_live() for live gap-free candles instead.",
482
+ DeprecationWarning,
483
+ stacklevel=2,
484
+ )
485
+ gen = self.get_candles_live(asset, period, hours=2.0)
486
+ closed, forming = await anext(gen)
487
+ return closed
459
488
 
460
489
  async def get_candles(self, asset: str, period: int, offset: int) -> List[Dict]:
461
490
  """
@@ -475,11 +504,24 @@ class PocketOptionAsync:
475
504
  - close: Closing price
476
505
 
477
506
  Note:
478
- Available timeframes: 1, 5, 15, 30, 60, 300 seconds
479
- Maximum period depends on the timeframe
480
- """
481
- candles = await self.client.get_candles(asset, period, offset)
482
- return json.loads(candles)
507
+ - Available timeframes: 1, 5, 15, 30, 60, 300 seconds
508
+ - Maximum period depends on the timeframe
509
+ - WARNING: This function only fetches closed historical candles and is intended
510
+ for training models, backtesting, or historical analysis. It is NOT designed
511
+ for real-time/live trading as it does not include the current forming candle
512
+ and can introduce gaps if called sequentially during live trading.
513
+ For live gap-free candle feeds, use `get_candles_live()` instead.
514
+ """
515
+ warnings.warn(
516
+ "get_candles() is deprecated and will be removed in a new release. "
517
+ "Please use get_candles_live() for live gap-free candles instead.",
518
+ DeprecationWarning,
519
+ stacklevel=2,
520
+ )
521
+ hours = max(0.1, offset / 3600.0)
522
+ gen = self.get_candles_live(asset, period, hours=hours)
523
+ closed, forming = await anext(gen)
524
+ return closed
483
525
 
484
526
  async def get_candles_advanced(self, asset: str, period: int, offset: int, time: int) -> List[Dict]:
485
527
  """
@@ -500,12 +542,209 @@ class PocketOptionAsync:
500
542
  - close: Closing price
501
543
 
502
544
  Note:
503
- Available timeframes: 1, 5, 15, 30, 60, 300 seconds
504
- Maximum period depends on the timeframe
545
+ - Available timeframes: 1, 5, 15, 30, 60, 300 seconds
546
+ - Maximum period depends on the timeframe
547
+ - WARNING: This function only fetches closed historical candles and is intended
548
+ for training models, backtesting, or historical analysis. It is NOT designed
549
+ for real-time/live trading as it does not include the current forming candle
550
+ and can introduce gaps if called sequentially during live trading.
551
+ For live gap-free candle feeds, use `get_candles_live()` instead.
505
552
  """
506
553
  candles = await self.client.get_candles_advanced(asset, period, offset, time)
507
554
  return json.loads(candles)
508
555
 
556
+ async def get_candles_live(
557
+ self,
558
+ asset: str,
559
+ period: int,
560
+ hours: float = 2.0,
561
+ max_rows: int = 100,
562
+ ) -> AsyncGenerator[Tuple[List[Dict], Optional[Dict]], None]:
563
+ """Fetches historical backfill and streams gap-free live candles.
564
+
565
+ This method subscribes to raw ticks first and buffers them, then fetches
566
+ historical candles (using get_candles_advanced, history, and compile_candles),
567
+ merges them, replays the buffered ticks, and yields updated candles (both
568
+ closed historical candles and the current forming candle) in real-time.
569
+
570
+ Args:
571
+ asset (str): Trading asset (e.g., "EURUSD_otc")
572
+ period (int): Candle timeframe in seconds (e.g., 60 for 1-minute candles)
573
+ hours (float): Hours of history to backfill. Defaults to 2.0.
574
+ max_rows (int): Maximum number of closed candles to retain in history. Defaults to 100.
575
+
576
+ Yields:
577
+ Tuple[List[Dict], Optional[Dict]]: A tuple containing:
578
+ - List[Dict]: List of closed candles (up to max_rows), each containing
579
+ 'time', 'open', 'high', 'low', 'close'.
580
+ - Optional[Dict]: The currently forming candle, containing 'time', 'open',
581
+ 'high', 'low', 'close', or None if not yet started.
582
+ """
583
+ platform_time_offset = 7200
584
+
585
+ def bucket_start(timestamp: int, p: int) -> int:
586
+ return (timestamp // p) * p
587
+
588
+ def extract_time(candle: Dict) -> int:
589
+ val = int(float(candle.get("timestamp", candle.get("time", 0))))
590
+ if val > 10_000_000_000:
591
+ val //= 1000
592
+ return val - platform_time_offset
593
+
594
+ def merge_candles(*groups: List[Dict]) -> List[Dict]:
595
+ res: Dict[int, Dict] = {}
596
+ for group in groups:
597
+ for candle in group:
598
+ res[extract_time(candle)] = candle
599
+ return [res[ts] for ts in sorted(res)]
600
+
601
+ # Initialize feed
602
+ feed_candles: deque = deque(maxlen=max_rows)
603
+ forming: Optional[Dict] = None
604
+
605
+ def seed_history(history: List[Dict]) -> None:
606
+ cutoff = bucket_start(int(time.time()), period)
607
+ ordered = sorted(
608
+ (c for c in history if extract_time(c) < cutoff),
609
+ key=extract_time,
610
+ )
611
+ for c in ordered[-max_rows:]:
612
+ feed_candles.append(
613
+ {
614
+ "time": extract_time(c),
615
+ "open": float(c["open"]),
616
+ "high": float(c["high"]),
617
+ "low": float(c["low"]),
618
+ "close": float(c["close"]),
619
+ }
620
+ )
621
+
622
+ def ingest_tick(timestamp: int, price: float) -> None:
623
+ nonlocal forming
624
+ if forming is None:
625
+ start = bucket_start(timestamp, period)
626
+ forming = {
627
+ "time": start,
628
+ "open": price,
629
+ "high": price,
630
+ "low": price,
631
+ "close": price,
632
+ }
633
+ return
634
+
635
+ start = bucket_start(timestamp, period)
636
+ if start == forming["time"]:
637
+ forming["high"] = max(forming["high"], price)
638
+ forming["low"] = min(forming["low"], price)
639
+ forming["close"] = price
640
+ elif start > forming["time"]:
641
+ feed_candles.append(dict(forming))
642
+ forming = {
643
+ "time": start,
644
+ "open": price,
645
+ "high": price,
646
+ "low": price,
647
+ "close": price,
648
+ }
649
+
650
+ # 1. Subscribe to ticks FIRST
651
+ tick_buffer: List[Tuple[int, float]] = []
652
+ buffering = True
653
+ stream = await self.subscribe_symbol(asset)
654
+
655
+ queue = asyncio.Queue()
656
+
657
+ async def tick_reader():
658
+ nonlocal buffering
659
+ try:
660
+ async for tick in stream:
661
+ ts = extract_time(tick)
662
+ price = float(tick.get("close", tick.get("price", 0.0)))
663
+ if buffering:
664
+ tick_buffer.append((ts, price))
665
+ else:
666
+ ingest_tick(ts, price)
667
+ await queue.put((list(feed_candles), dict(forming) if forming else None))
668
+ except asyncio.CancelledError:
669
+ pass
670
+ finally:
671
+ await queue.put(None)
672
+
673
+ reader_task = asyncio.create_task(tick_reader())
674
+
675
+ try:
676
+ # 2. Fetch history while buffering ticks
677
+ offset_seconds = int(hours * 3600)
678
+ platform_time = int(time.time()) + platform_time_offset
679
+
680
+ try:
681
+ advanced_candles = await asyncio.wait_for(
682
+ self.get_candles_advanced(
683
+ asset,
684
+ period,
685
+ offset_seconds,
686
+ platform_time,
687
+ ),
688
+ timeout=3.0
689
+ )
690
+ except Exception:
691
+ advanced_candles = []
692
+
693
+ try:
694
+ recent_candles = await asyncio.wait_for(
695
+ self.history(asset, period),
696
+ timeout=3.0
697
+ )
698
+ except Exception:
699
+ recent_candles = []
700
+
701
+ try:
702
+ compiled_candles = await asyncio.wait_for(
703
+ self.compile_candles(
704
+ asset,
705
+ period,
706
+ offset_seconds,
707
+ ),
708
+ timeout=3.0
709
+ )
710
+ except Exception:
711
+ compiled_candles = []
712
+
713
+ history = merge_candles(
714
+ compiled_candles,
715
+ recent_candles,
716
+ advanced_candles,
717
+ )
718
+ seed_history(history)
719
+
720
+ # 3. Replay backlog
721
+ cutoff = 0
722
+ if feed_candles:
723
+ cutoff = feed_candles[-1]["time"] + period
724
+ for ts, price in sorted(tick_buffer):
725
+ if ts < cutoff:
726
+ continue
727
+ ingest_tick(ts, price)
728
+
729
+ buffering = False
730
+ # Yield initial seed state
731
+ yield list(feed_candles), dict(forming) if forming else None
732
+
733
+ # 4. Stream loop
734
+ while True:
735
+ item = await queue.get()
736
+ if item is None:
737
+ break
738
+ yield item
739
+
740
+ finally:
741
+ reader_task.cancel()
742
+ try:
743
+ await reader_task
744
+ except asyncio.CancelledError:
745
+ pass
746
+ await self.unsubscribe(asset)
747
+
509
748
  async def balance(self) -> float:
510
749
  """
511
750
  Retrieves current account balance.
@@ -987,6 +1226,14 @@ class PocketOptionAsync:
987
1226
 
988
1227
  return json.loads(await self.client.compile_candles(asset, custom_period, lookback_period))
989
1228
 
1229
+ async def send_raw(self, message: str) -> None:
1230
+ """Send a raw Engine.io/Socket.io message directly over the connection."""
1231
+ await self.client.send_raw(message)
1232
+
1233
+ async def subscribe_raw(self) -> AsyncRawSubscription:
1234
+ """Subscribe to all incoming WebSocket messages verbatim."""
1235
+ return AsyncRawSubscription(await self.client.subscribe_raw())
1236
+
990
1237
  async def subscribe_symbol(self, asset: str) -> AsyncSubscription:
991
1238
  """Subscribe to real-time raw price updates for an asset.
992
1239
 
@@ -1128,15 +1375,6 @@ class PocketOptionAsync:
1128
1375
  """Returns whether the SSID passed basic format validation during init."""
1129
1376
  return self._ssid_valid
1130
1377
 
1131
- def max_subscriptions(self) -> int:
1132
- """
1133
- Returns the configured maximum number of concurrent subscriptions.
1134
-
1135
- Returns:
1136
- int: Maximum number of concurrent asset subscriptions allowed
1137
- """
1138
- return self.client.max_subscriptions()
1139
-
1140
1378
  async def disconnect(self) -> None:
1141
1379
  """
1142
1380
  Disconnects the client while keeping the configuration intact.
@@ -1,10 +1,10 @@
1
1
  import asyncio
2
2
  import json
3
3
  import threading
4
+ import sys
5
+ import warnings
4
6
  from datetime import timedelta
5
7
  from typing import Dict, List, Optional, Tuple, Union
6
- import sys
7
-
8
8
  from ..config import Config
9
9
  from ..validator import Validator as Validator
10
10
  from .asynchronous import PocketOptionAsync as PocketOptionAsync
@@ -25,6 +25,41 @@ class SyncSubscription:
25
25
  return json.loads(next(self.subscription))
26
26
 
27
27
 
28
+ class SyncRawSubscription:
29
+ def __init__(self, subscription):
30
+ self.subscription = subscription
31
+
32
+ def __iter__(self):
33
+ return self
34
+
35
+ def __aiter__(self):
36
+ return self.subscription
37
+
38
+ def __next__(self):
39
+ return next(self.subscription)
40
+
41
+
42
+ class SyncCandleLiveIterator:
43
+ """Synchronous iterator for live candle updates."""
44
+
45
+ def __init__(self, async_gen, loop):
46
+ self.async_gen = async_gen
47
+ self.loop = loop
48
+
49
+ def __iter__(self):
50
+ return self
51
+
52
+ def __next__(self):
53
+ async def get_next():
54
+ try:
55
+ return await self.async_gen.__anext__()
56
+ except StopAsyncIteration:
57
+ raise StopIteration
58
+
59
+ try:
60
+ return asyncio.run_coroutine_threadsafe(get_next(), self.loop).result()
61
+ except StopIteration:
62
+ raise StopIteration
28
63
  class RawHandlerSync:
29
64
  """Synchronous handler for advanced raw WebSocket message operations."""
30
65
 
@@ -126,11 +161,14 @@ class PocketOption:
126
161
  _: Additional keyword arguments forwarded to the async client.
127
162
  """
128
163
  self._lock = threading.RLock()
129
- self._loop = asyncio.new_event_loop()
130
- def _run_loop():
131
- asyncio.set_event_loop(self._loop)
132
- self._loop.run_forever()
133
- self._loop_thread = threading.Thread(target=_run_loop, daemon=True)
164
+ loop = asyncio.new_event_loop()
165
+ self._loop = loop
166
+
167
+ def _run_loop(loop_to_run):
168
+ asyncio.set_event_loop(loop_to_run)
169
+ loop_to_run.run_forever()
170
+
171
+ self._loop_thread = threading.Thread(target=_run_loop, args=(loop,), daemon=True)
134
172
  self._loop_thread.start()
135
173
  self._client = PocketOptionAsync(ssid, url=url, config=config)
136
174
  future = asyncio.run_coroutine_threadsafe(self._client.wait_for_assets(), self._loop)
@@ -138,7 +176,7 @@ class PocketOption:
138
176
 
139
177
  def __del__(self):
140
178
  self._cleanup_loop()
141
-
179
+
142
180
  def _cleanup_loop(self):
143
181
  loop = getattr(self, "_loop", None)
144
182
  if loop is None or loop.is_closed():
@@ -150,7 +188,7 @@ class PocketOption:
150
188
  future.result(timeout=5)
151
189
  except Exception:
152
190
  pass
153
-
191
+
154
192
  loop.call_soon_threadsafe(loop.stop)
155
193
  thread = getattr(self, "_loop_thread", None)
156
194
  if thread is not None and thread.is_alive():
@@ -158,7 +196,7 @@ class PocketOption:
158
196
  # The daemon thread will be killed automatically, so just skip the join.
159
197
  if not sys.is_finalizing():
160
198
  thread.join(timeout=2)
161
-
199
+
162
200
  try:
163
201
  loop.close()
164
202
  except Exception:
@@ -270,8 +308,24 @@ class PocketOption:
270
308
 
271
309
  Returns:
272
310
  A list of candle dictionaries.
273
- """
274
- return self._run(self._client.get_candles(asset, period, offset))
311
+
312
+ Note:
313
+ WARNING: This function only fetches closed historical candles and is intended
314
+ for training models, backtesting, or historical analysis. It is NOT designed
315
+ for real-time/live trading as it does not include the current forming candle
316
+ and can introduce gaps if called sequentially during live trading.
317
+ For live gap-free candle feeds, use `get_candles_live()` instead.
318
+ """
319
+ warnings.warn(
320
+ "get_candles() is deprecated and will be removed in a new release. "
321
+ "Please use get_candles_live() for live gap-free candles instead.",
322
+ DeprecationWarning,
323
+ stacklevel=2,
324
+ )
325
+ hours = max(0.1, offset / 3600.0)
326
+ iterator = self.get_candles_live(asset, period, hours=hours)
327
+ closed, forming = next(iterator)
328
+ return closed
275
329
 
276
330
  def get_candles_advanced(self, asset: str, period: int, offset: int, time: int) -> List[Dict]:
277
331
  """Get historical candle data with a specific reference time.
@@ -284,6 +338,13 @@ class PocketOption:
284
338
 
285
339
  Returns:
286
340
  A list of candle dictionaries.
341
+
342
+ Note:
343
+ WARNING: This function only fetches closed historical candles and is intended
344
+ for training models, backtesting, or historical analysis. It is NOT designed
345
+ for real-time/live trading as it does not include the current forming candle
346
+ and can introduce gaps if called sequentially during live trading.
347
+ For live gap-free candle feeds, use `get_candles_live()` instead.
287
348
  """
288
349
  return self._run(self._client.get_candles_advanced(asset, period, offset, time))
289
350
 
@@ -296,8 +357,57 @@ class PocketOption:
296
357
 
297
358
  Returns:
298
359
  A list of candle dictionaries.
360
+
361
+ Note:
362
+ WARNING: This function only fetches closed historical candles and is intended
363
+ for training models, backtesting, or historical analysis. It is NOT designed
364
+ for real-time/live trading as it does not include the current forming candle
365
+ and can introduce gaps if called sequentially during live trading.
366
+ For live gap-free candle feeds, use `get_candles_live()` instead.
367
+ """
368
+ warnings.warn(
369
+ "candles() is deprecated and will be removed in a new release. "
370
+ "Please use get_candles_live() for live gap-free candles instead.",
371
+ DeprecationWarning,
372
+ stacklevel=2,
373
+ )
374
+ iterator = self.get_candles_live(asset, period, hours=2.0)
375
+ closed, forming = next(iterator)
376
+ return closed
377
+
378
+ def get_candles_live(
379
+ self,
380
+ asset: str,
381
+ period: int,
382
+ hours: float = 2.0,
383
+ max_rows: int = 100,
384
+ ) -> SyncCandleLiveIterator:
385
+ """Fetches historical backfill and streams live candles.
386
+
387
+ This method subscribes to raw ticks first and buffers them, then fetches
388
+ historical candles, merges them, replays the buffered ticks, and returns
389
+ a generator yielding updated candles (both closed historical candles and
390
+ the current forming candle) in real-time.
391
+
392
+ Args:
393
+ asset: Trading asset (e.g., "EURUSD_otc")
394
+ period: Candle timeframe in seconds (e.g., 60 for 1-minute candles)
395
+ hours: Hours of history to backfill. Defaults to 2.0.
396
+ max_rows: Maximum number of closed candles to retain in history. Defaults to 100.
397
+
398
+ Returns:
399
+ An iterator yielding (closed_candles, forming_candle).
299
400
  """
300
- return self._run(self._client.candles(asset, period))
401
+ async def create_gen():
402
+ return self._client.get_candles_live(
403
+ asset=asset,
404
+ period=period,
405
+ hours=hours,
406
+ max_rows=max_rows,
407
+ )
408
+
409
+ async_gen = self._run(create_gen())
410
+ return SyncCandleLiveIterator(async_gen, self.loop)
301
411
 
302
412
  def balance(self) -> float:
303
413
  """Get the current account balance.
@@ -442,6 +552,14 @@ class PocketOption:
442
552
  """
443
553
  return self._run(self._client.compile_candles(asset, custom_period, lookback_period))
444
554
 
555
+ def send_raw(self, message: str) -> None:
556
+ """Send a raw Engine.io/Socket.io message directly over the connection."""
557
+ self._run(self._client.send_raw(message))
558
+
559
+ def subscribe_raw(self) -> SyncRawSubscription:
560
+ """Subscribe to all incoming WebSocket messages verbatim."""
561
+ return SyncRawSubscription(self._run(self._client.subscribe_raw()))
562
+
445
563
  def subscribe_symbol(self, asset: str) -> SyncSubscription:
446
564
  """Subscribe to real-time price updates for a symbol.
447
565
 
@@ -537,14 +655,6 @@ class PocketOption:
537
655
  """
538
656
  return self._client.is_connected()
539
657
 
540
- def max_subscriptions(self) -> int:
541
- """Get the maximum number of concurrent subscriptions.
542
-
543
- Returns:
544
- The maximum number of allowed subscriptions.
545
- """
546
- return self._client.max_subscriptions()
547
-
548
658
  def wait_for_assets(self, timeout: float = 60.0) -> None:
549
659
  """Wait for asset data to finish loading.
550
660