├── .github └── workflows │ ├── CI.yml │ └── JsPublish.yml ├── .gitignore ├── BinaryOptionsToolsJs ├── .cargo │ └── config.toml ├── .github │ └── workflows │ │ └── CI.yml ├── .gitignore ├── .npmignore ├── .yarn │ └── releases │ │ └── yarn-4.7.0.cjs ├── .yarnrc.yml ├── CONTRIBUTING.md ├── Cargo.toml ├── README.md ├── __test__ │ └── index.spec.mjs ├── build.rs ├── index.d.ts ├── index.js ├── npm │ ├── android-arm-eabi │ │ ├── README.md │ │ └── package.json │ ├── android-arm64 │ │ ├── README.md │ │ └── package.json │ ├── darwin-arm64 │ │ ├── README.md │ │ └── package.json │ ├── darwin-universal │ │ ├── README.md │ │ └── package.json │ ├── darwin-x64 │ │ ├── README.md │ │ └── package.json │ ├── freebsd-x64 │ │ ├── README.md │ │ └── package.json │ ├── linux-arm-gnueabihf │ │ ├── README.md │ │ └── package.json │ ├── linux-arm-musleabihf │ │ ├── README.md │ │ └── package.json │ ├── linux-arm64-gnu │ │ ├── README.md │ │ └── package.json │ ├── linux-arm64-musl │ │ ├── README.md │ │ └── package.json │ ├── linux-riscv64-gnu │ │ ├── README.md │ │ └── package.json │ ├── linux-x64-gnu │ │ ├── README.md │ │ └── package.json │ ├── linux-x64-musl │ │ ├── README.md │ │ └── package.json │ ├── win32-arm64-msvc │ │ ├── README.md │ │ └── package.json │ ├── win32-ia32-msvc │ │ ├── README.md │ │ └── package.json │ └── win32-x64-msvc │ │ ├── README.md │ │ └── package.json ├── package-lock.json ├── package.json ├── rustfmt.toml ├── src │ ├── error.rs │ ├── lib.rs │ ├── logs.rs │ ├── pocketoption.rs │ ├── runtime.rs │ └── validator.rs ├── wrapper │ └── index.js └── yarn.lock ├── BinaryOptionsToolsV2 ├── .github │ └── workflows │ │ └── CI.yml ├── .gitignore ├── BinaryOptionsToolsV2 │ ├── __init__.py │ ├── config.py │ ├── pocketoption │ │ ├── __init__.py │ │ ├── asyncronous.py │ │ └── syncronous.py │ ├── tracing.py │ └── validator.py ├── Cargo.lock ├── Cargo.toml ├── Dockerfile ├── Readme.md ├── candles_eurusd_otc.csv ├── pyproject.toml ├── src │ ├── config.rs │ ├── error.rs │ ├── lib.rs │ ├── logs.rs │ ├── pocketoption.rs │ ├── runtime.rs │ ├── stream.rs │ └── validator.rs ├── tests │ ├── test.py │ └── test_sync.py └── uv.lock ├── CI.yml ├── LICENSE ├── README.md ├── crates ├── binary_options_tools │ ├── .gitignore │ ├── Cargo.lock │ ├── Cargo.toml │ ├── Readme.md │ ├── errors.log │ ├── src │ │ ├── lib.rs │ │ ├── pocketoption │ │ │ ├── error.rs │ │ │ ├── mod.rs │ │ │ ├── parser │ │ │ │ ├── basic.rs │ │ │ │ ├── message.rs │ │ │ │ └── mod.rs │ │ │ ├── pocket_client.rs │ │ │ ├── types │ │ │ │ ├── base.rs │ │ │ │ ├── callback.rs │ │ │ │ ├── data.rs │ │ │ │ ├── info.rs │ │ │ │ ├── mod.rs │ │ │ │ ├── order.rs │ │ │ │ ├── success.rs │ │ │ │ └── update.rs │ │ │ ├── utils │ │ │ │ ├── basic.rs │ │ │ │ ├── connect.rs │ │ │ │ ├── location.rs │ │ │ │ └── mod.rs │ │ │ ├── validators.rs │ │ │ └── ws │ │ │ │ ├── connect.rs │ │ │ │ ├── listener.rs │ │ │ │ ├── mod.rs │ │ │ │ ├── regions.json │ │ │ │ ├── regions.rs │ │ │ │ ├── ssid.rs │ │ │ │ └── stream.rs │ │ └── reimports.rs │ └── tests │ │ ├── assets.txt │ │ ├── assets2.json │ │ ├── data.json │ │ ├── fail_open_pending_order.json │ │ ├── fail_open_pending_order2.json │ │ ├── load_history_period.json │ │ ├── load_history_period2.json │ │ ├── success_open_order.json │ │ ├── success_open_pending_order.json │ │ ├── success_update_pending.json │ │ ├── test.json │ │ ├── test_close_order.txt │ │ ├── test_demo.json │ │ ├── update_close_order.json │ │ ├── update_closed_deals.txt │ │ ├── update_history_new.json │ │ └── update_opened_deals.txt ├── core │ ├── .gitignore │ ├── Cargo.lock │ ├── Cargo.toml │ ├── errors.log │ ├── readme.md │ └── src │ │ ├── constants.rs │ │ ├── error.rs │ │ ├── general │ │ ├── client.rs │ │ ├── config.rs │ │ ├── mod.rs │ │ ├── send.rs │ │ ├── stream.rs │ │ ├── traits.rs │ │ ├── types.rs │ │ └── validate.rs │ │ ├── lib.rs │ │ ├── reimports.rs │ │ └── utils │ │ ├── mod.rs │ │ ├── time.rs │ │ └── tracing.rs └── macros │ ├── .gitignore │ ├── Cargo.lock │ ├── Cargo.toml │ ├── readme.md │ └── src │ ├── config.rs │ ├── deserialize.rs │ ├── impls │ └── mod.rs │ ├── lib.rs │ ├── region.rs │ ├── serialize.rs │ └── timeout.rs ├── data ├── OTC-assets.txt ├── assets-otc.tested.txt └── assets.txt ├── docker ├── android │ └── Dockerfile ├── linux │ └── Dockerfile ├── macos │ └── Dockerfile └── windows │ └── Dockerfile ├── docs ├── .nojekyll ├── DEPLOYMENT.md ├── DOCUMENTATION_SUMMARY.md ├── README.md ├── _config.yml ├── api.html ├── assets │ ├── css │ │ ├── animations.css │ │ ├── code-highlight.css │ │ └── main.css │ ├── images │ │ └── logo.svg │ └── js │ │ ├── animations.js │ │ ├── api.js │ │ ├── code-highlight.js │ │ ├── examples.js │ │ └── main.js ├── examples.html ├── favicon.svg ├── index.html ├── javascript.html ├── python.html ├── robots.txt ├── rust.html └── sitemap.xml ├── examples ├── .gitignore ├── javascript │ ├── .gitignore │ ├── binary-options-tools.node │ ├── check_win.js │ ├── create_raw_iterator.js │ ├── create_raw_order.js │ ├── get_balance.js │ ├── get_candles.js │ ├── get_deal_end_time.js │ ├── history.js │ ├── logs.js │ ├── payout.js │ ├── raw_send.js │ ├── stream.js │ ├── stream_chunked.js │ └── validator.js └── python │ ├── .gitignore │ ├── async │ ├── LLM-context.py │ ├── check_win.py │ ├── context.txt │ ├── create_raw_iterator.py │ ├── create_raw_order.py │ ├── get_balance.py │ ├── get_candles.py │ ├── get_open_and_close_trades.py │ ├── history.py │ ├── log_iterator.py │ ├── login_with_email_and_password.py │ ├── logs.py │ ├── payout.py │ ├── raw_send.py │ ├── subscribe_symbol.py │ ├── subscribe_symbol_chuncked.py │ ├── subscribe_symbol_timed.py │ ├── trade.py │ └── validator.py │ └── sync │ ├── check_win.py │ ├── create_raw_iterator.py │ ├── create_raw_order.py │ ├── get_balance.py │ ├── get_candles.py │ ├── get_open_and_close_trades.py │ ├── history.py │ ├── log_iterator.py │ ├── logs.py │ ├── payout.py │ ├── raw_send.py │ ├── subscribe_symbol.py │ ├── subscribe_symbol_chuncked.py │ ├── subscribe_symbol_timed.py │ ├── trade.py │ └── validator.py ├── logs └── errors.log ├── tests ├── assets.txt └── test-assets.py └── tutorials └── How to get SSID.docx /.gitignore: -------------------------------------------------------------------------------- 1 | /core/target 2 | /rust/target 3 | /examples/*.log 4 | .qodo 5 | -------------------------------------------------------------------------------- /BinaryOptionsToolsJs/.cargo/config.toml: -------------------------------------------------------------------------------- 1 | [target.aarch64-unknown-linux-musl] 2 | linker = "aarch64-linux-musl-gcc" 3 | rustflags = ["-C", "target-feature=-crt-static"] 4 | [target.x86_64-pc-windows-msvc] 5 | rustflags = ["-C", "target-feature=+crt-static"] -------------------------------------------------------------------------------- /BinaryOptionsToolsJs/.gitignore: -------------------------------------------------------------------------------- 1 | # Created by https://www.toptal.com/developers/gitignore/api/node 2 | # Edit at https://www.toptal.com/developers/gitignore?templates=node 3 | 4 | ### Node ### 5 | # Logs 6 | logs 7 | *.log 8 | npm-debug.log* 9 | yarn-debug.log* 10 | yarn-error.log* 11 | lerna-debug.log* 12 | 13 | # Diagnostic reports (https://nodejs.org/api/report.html) 14 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json 15 | 16 | # Runtime data 17 | pids 18 | *.pid 19 | *.seed 20 | *.pid.lock 21 | 22 | # Directory for instrumented libs generated by jscoverage/JSCover 23 | lib-cov 24 | 25 | # Coverage directory used by tools like istanbul 26 | coverage 27 | *.lcov 28 | 29 | # nyc test coverage 30 | .nyc_output 31 | 32 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) 33 | .grunt 34 | 35 | # Bower dependency directory (https://bower.io/) 36 | bower_components 37 | 38 | # node-waf configuration 39 | .lock-wscript 40 | 41 | # Compiled binary addons (https://nodejs.org/api/addons.html) 42 | build/Release 43 | 44 | # Dependency directories 45 | node_modules/ 46 | jspm_packages/ 47 | 48 | # TypeScript v1 declaration files 49 | typings/ 50 | 51 | # TypeScript cache 52 | *.tsbuildinfo 53 | 54 | # Optional npm cache directory 55 | .npm 56 | 57 | # Optional eslint cache 58 | .eslintcache 59 | 60 | # Microbundle cache 61 | .rpt2_cache/ 62 | .rts2_cache_cjs/ 63 | .rts2_cache_es/ 64 | .rts2_cache_umd/ 65 | 66 | # Optional REPL history 67 | .node_repl_history 68 | 69 | # Output of 'npm pack' 70 | *.tgz 71 | 72 | # Yarn Integrity file 73 | .yarn-integrity 74 | 75 | # dotenv environment variables file 76 | .env 77 | .env.test 78 | 79 | # parcel-bundler cache (https://parceljs.org/) 80 | .cache 81 | 82 | # Next.js build output 83 | .next 84 | 85 | # Nuxt.js build / generate output 86 | .nuxt 87 | dist 88 | 89 | # Gatsby files 90 | .cache/ 91 | # Comment in the public line in if your project uses Gatsby and not Next.js 92 | # https://nextjs.org/blog/next-9-1#public-directory-support 93 | # public 94 | 95 | # vuepress build output 96 | .vuepress/dist 97 | 98 | # Serverless directories 99 | .serverless/ 100 | 101 | # FuseBox cache 102 | .fusebox/ 103 | 104 | # DynamoDB Local files 105 | .dynamodb/ 106 | 107 | # TernJS port file 108 | .tern-port 109 | 110 | # Stores VSCode versions used for testing VSCode extensions 111 | .vscode-test 112 | 113 | # End of https://www.toptal.com/developers/gitignore/api/node 114 | 115 | # Created by https://www.toptal.com/developers/gitignore/api/macos 116 | # Edit at https://www.toptal.com/developers/gitignore?templates=macos 117 | 118 | ### macOS ### 119 | # General 120 | .DS_Store 121 | .AppleDouble 122 | .LSOverride 123 | 124 | # Icon must end with two 125 | Icon 126 | 127 | 128 | # Thumbnails 129 | ._* 130 | 131 | # Files that might appear in the root of a volume 132 | .DocumentRevisions-V100 133 | .fseventsd 134 | .Spotlight-V100 135 | .TemporaryItems 136 | .Trashes 137 | .VolumeIcon.icns 138 | .com.apple.timemachine.donotpresent 139 | 140 | # Directories potentially created on remote AFP share 141 | .AppleDB 142 | .AppleDesktop 143 | Network Trash Folder 144 | Temporary Items 145 | .apdisk 146 | 147 | ### macOS Patch ### 148 | # iCloud generated files 149 | *.icloud 150 | 151 | # End of https://www.toptal.com/developers/gitignore/api/macos 152 | 153 | # Created by https://www.toptal.com/developers/gitignore/api/windows 154 | # Edit at https://www.toptal.com/developers/gitignore?templates=windows 155 | 156 | ### Windows ### 157 | # Windows thumbnail cache files 158 | Thumbs.db 159 | Thumbs.db:encryptable 160 | ehthumbs.db 161 | ehthumbs_vista.db 162 | 163 | # Dump file 164 | *.stackdump 165 | 166 | # Folder config file 167 | [Dd]esktop.ini 168 | 169 | # Recycle Bin used on file shares 170 | $RECYCLE.BIN/ 171 | 172 | # Windows Installer files 173 | *.cab 174 | *.msi 175 | *.msix 176 | *.msm 177 | *.msp 178 | 179 | # Windows shortcuts 180 | *.lnk 181 | 182 | # End of https://www.toptal.com/developers/gitignore/api/windows 183 | 184 | #Added by cargo 185 | 186 | /target 187 | Cargo.lock 188 | 189 | .pnp.* 190 | .yarn/* 191 | !.yarn/patches 192 | !.yarn/plugins 193 | !.yarn/releases 194 | !.yarn/sdks 195 | !.yarn/versions 196 | 197 | *.node 198 | -------------------------------------------------------------------------------- /BinaryOptionsToolsJs/.npmignore: -------------------------------------------------------------------------------- 1 | target 2 | Cargo.lock 3 | .cargo 4 | .github 5 | npm 6 | .eslintrc 7 | .prettierignore 8 | rustfmt.toml 9 | yarn.lock 10 | *.node 11 | .yarn 12 | __test__ 13 | renovate.json 14 | -------------------------------------------------------------------------------- /BinaryOptionsToolsJs/.yarnrc.yml: -------------------------------------------------------------------------------- 1 | nodeLinker: node-modules 2 | 3 | yarnPath: .yarn/releases/yarn-4.7.0.cjs 4 | -------------------------------------------------------------------------------- /BinaryOptionsToolsJs/CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing to Binary Options Tools JS 2 | 3 | We love your input! We want to make contributing as easy and transparent as possible. 4 | 5 | ## Development Setup 6 | 7 | 1. Install Rust and Node.js 8 | ```bash 9 | # Install Rust 10 | curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh 11 | 12 | # Install Node.js dependencies 13 | yarn install 14 | ``` 15 | 16 | 2. Build the project 17 | ```bash 18 | yarn build 19 | ``` 20 | 21 | 3. Run tests 22 | ```bash 23 | yarn test 24 | ``` 25 | 26 | ## Making Changes 27 | 28 | 1. Fork the repo 29 | 2. Create your feature branch (`git checkout -b feature/amazing-feature`) 30 | 3. Make your changes 31 | 4. Run the tests (`yarn test`) 32 | 5. Commit your changes (`git commit -m 'Add amazing feature'`) 33 | 6. Push to the branch (`git push origin feature/amazing-feature`) 34 | 7. Create a Pull Request 35 | 36 | ## Coding Style 37 | 38 | - Follow the existing code style 39 | - Use TypeScript for new JavaScript code 40 | - Document all public APIs 41 | - Add tests for new features 42 | 43 | ## License 44 | 45 | By contributing, you agree that your contributions will be licensed under the MIT License. -------------------------------------------------------------------------------- /BinaryOptionsToolsJs/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | edition = "2021" 3 | name = "binary-options-tools" 4 | version = "0.1.1" 5 | 6 | [lib] 7 | crate-type = ["cdylib"] 8 | 9 | [dependencies] 10 | # Default enable napi4 feature, see https://nodejs.org/api/n-api.html#node-api-version-matrix 11 | napi = { version = "2.16.17", default-features = false, features = [ 12 | "napi4", 13 | "tokio_rt", 14 | "serde-json", 15 | ] } 16 | napi-derive = "2.12.2" 17 | binary-options-tools = { path = "../crates/binary_options_tools", version = "0.1.7" } 18 | thiserror = "2.0.12" 19 | serde = { version = "1.0.219", features = ["derive"] } 20 | serde_json = "1.0.140" 21 | uuid = "1.16.0" 22 | tracing = "0.1.41" 23 | tokio = "1.44.2" 24 | futures-util = "0.3.31" 25 | url = "2.5.4" 26 | chrono = "0.4.41" 27 | regex = "1.11.1" 28 | tracing-subscriber = { version = "0.3.19", features = ["env-filter"] } 29 | once_cell = "1.21.3" 30 | 31 | [build-dependencies] 32 | napi-build = "2.1.6" 33 | 34 | [profile.release] 35 | lto = true 36 | strip = "symbols" 37 | -------------------------------------------------------------------------------- /BinaryOptionsToolsJs/__test__/index.spec.mjs: -------------------------------------------------------------------------------- 1 | import test from 'ava' 2 | 3 | import { sum } from '../index.js' 4 | 5 | test('sum from native', (t) => { 6 | t.is(sum(1, 2), 3) 7 | }) 8 | -------------------------------------------------------------------------------- /BinaryOptionsToolsJs/build.rs: -------------------------------------------------------------------------------- 1 | extern crate napi_build; 2 | 3 | fn main() { 4 | napi_build::setup(); 5 | } 6 | -------------------------------------------------------------------------------- /BinaryOptionsToolsJs/npm/android-arm-eabi/README.md: -------------------------------------------------------------------------------- 1 | # `@rick-29/binary-options-tools-android-arm-eabi` 2 | 3 | This is the **armv7-linux-androideabi** binary for `@rick-29/binary-options-tools` 4 | -------------------------------------------------------------------------------- /BinaryOptionsToolsJs/npm/android-arm-eabi/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@rick-29/binary-options-tools-android-arm-eabi", 3 | "version": "0.0.0", 4 | "os": [ 5 | "android" 6 | ], 7 | "cpu": [ 8 | "arm" 9 | ], 10 | "main": "@rick-29/binary-options-tools.android-arm-eabi.node", 11 | "files": [ 12 | "@rick-29/binary-options-tools.android-arm-eabi.node" 13 | ], 14 | "license": "MIT", 15 | "engines": { 16 | "node": ">= 10" 17 | } 18 | } -------------------------------------------------------------------------------- /BinaryOptionsToolsJs/npm/android-arm64/README.md: -------------------------------------------------------------------------------- 1 | # `@rick-29/binary-options-tools-android-arm64` 2 | 3 | This is the **aarch64-linux-android** binary for `@rick-29/binary-options-tools` 4 | -------------------------------------------------------------------------------- /BinaryOptionsToolsJs/npm/android-arm64/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@rick-29/binary-options-tools-android-arm64", 3 | "version": "0.0.0", 4 | "os": [ 5 | "android" 6 | ], 7 | "cpu": [ 8 | "arm64" 9 | ], 10 | "main": "@rick-29/binary-options-tools.android-arm64.node", 11 | "files": [ 12 | "@rick-29/binary-options-tools.android-arm64.node" 13 | ], 14 | "license": "MIT", 15 | "engines": { 16 | "node": ">= 10" 17 | } 18 | } -------------------------------------------------------------------------------- /BinaryOptionsToolsJs/npm/darwin-arm64/README.md: -------------------------------------------------------------------------------- 1 | # `@rick-29/binary-options-tools-darwin-arm64` 2 | 3 | This is the **aarch64-apple-darwin** binary for `@rick-29/binary-options-tools` 4 | -------------------------------------------------------------------------------- /BinaryOptionsToolsJs/npm/darwin-arm64/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@rick-29/binary-options-tools-darwin-arm64", 3 | "version": "0.0.0", 4 | "os": [ 5 | "darwin" 6 | ], 7 | "cpu": [ 8 | "arm64" 9 | ], 10 | "main": "@rick-29/binary-options-tools.darwin-arm64.node", 11 | "files": [ 12 | "@rick-29/binary-options-tools.darwin-arm64.node" 13 | ], 14 | "license": "MIT", 15 | "engines": { 16 | "node": ">= 10" 17 | } 18 | } -------------------------------------------------------------------------------- /BinaryOptionsToolsJs/npm/darwin-universal/README.md: -------------------------------------------------------------------------------- 1 | # `@rick-29/binary-options-tools-darwin-universal` 2 | 3 | This is the **universal-apple-darwin** binary for `@rick-29/binary-options-tools` 4 | -------------------------------------------------------------------------------- /BinaryOptionsToolsJs/npm/darwin-universal/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@rick-29/binary-options-tools-darwin-universal", 3 | "version": "0.0.0", 4 | "os": [ 5 | "darwin" 6 | ], 7 | "main": "@rick-29/binary-options-tools.darwin-universal.node", 8 | "files": [ 9 | "@rick-29/binary-options-tools.darwin-universal.node" 10 | ], 11 | "license": "MIT", 12 | "engines": { 13 | "node": ">= 10" 14 | } 15 | } -------------------------------------------------------------------------------- /BinaryOptionsToolsJs/npm/darwin-x64/README.md: -------------------------------------------------------------------------------- 1 | # `@rick-29/binary-options-tools-darwin-x64` 2 | 3 | This is the **x86_64-apple-darwin** binary for `@rick-29/binary-options-tools` 4 | -------------------------------------------------------------------------------- /BinaryOptionsToolsJs/npm/darwin-x64/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@rick-29/binary-options-tools-darwin-x64", 3 | "version": "0.0.0", 4 | "os": [ 5 | "darwin" 6 | ], 7 | "cpu": [ 8 | "x64" 9 | ], 10 | "main": "@rick-29/binary-options-tools.darwin-x64.node", 11 | "files": [ 12 | "@rick-29/binary-options-tools.darwin-x64.node" 13 | ], 14 | "license": "MIT", 15 | "engines": { 16 | "node": ">= 10" 17 | } 18 | } -------------------------------------------------------------------------------- /BinaryOptionsToolsJs/npm/freebsd-x64/README.md: -------------------------------------------------------------------------------- 1 | # `@rick-29/binary-options-tools-freebsd-x64` 2 | 3 | This is the **x86_64-unknown-freebsd** binary for `@rick-29/binary-options-tools` 4 | -------------------------------------------------------------------------------- /BinaryOptionsToolsJs/npm/freebsd-x64/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@rick-29/binary-options-tools-freebsd-x64", 3 | "version": "0.0.0", 4 | "os": [ 5 | "freebsd" 6 | ], 7 | "cpu": [ 8 | "x64" 9 | ], 10 | "main": "@rick-29/binary-options-tools.freebsd-x64.node", 11 | "files": [ 12 | "@rick-29/binary-options-tools.freebsd-x64.node" 13 | ], 14 | "license": "MIT", 15 | "engines": { 16 | "node": ">= 10" 17 | } 18 | } -------------------------------------------------------------------------------- /BinaryOptionsToolsJs/npm/linux-arm-gnueabihf/README.md: -------------------------------------------------------------------------------- 1 | # `@rick-29/binary-options-tools-linux-arm-gnueabihf` 2 | 3 | This is the **armv7-unknown-linux-gnueabihf** binary for `@rick-29/binary-options-tools` 4 | -------------------------------------------------------------------------------- /BinaryOptionsToolsJs/npm/linux-arm-gnueabihf/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@rick-29/binary-options-tools-linux-arm-gnueabihf", 3 | "version": "0.0.0", 4 | "os": [ 5 | "linux" 6 | ], 7 | "cpu": [ 8 | "arm" 9 | ], 10 | "main": "@rick-29/binary-options-tools.linux-arm-gnueabihf.node", 11 | "files": [ 12 | "@rick-29/binary-options-tools.linux-arm-gnueabihf.node" 13 | ], 14 | "license": "MIT", 15 | "engines": { 16 | "node": ">= 10" 17 | } 18 | } -------------------------------------------------------------------------------- /BinaryOptionsToolsJs/npm/linux-arm-musleabihf/README.md: -------------------------------------------------------------------------------- 1 | # `@rick-29/binary-options-tools-linux-arm-musleabihf` 2 | 3 | This is the **armv7-unknown-linux-musleabihf** binary for `@rick-29/binary-options-tools` 4 | -------------------------------------------------------------------------------- /BinaryOptionsToolsJs/npm/linux-arm-musleabihf/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@rick-29/binary-options-tools-linux-arm-musleabihf", 3 | "version": "0.0.0", 4 | "os": [ 5 | "linux" 6 | ], 7 | "cpu": [ 8 | "arm" 9 | ], 10 | "main": "@rick-29/binary-options-tools.linux-arm-musleabihf.node", 11 | "files": [ 12 | "@rick-29/binary-options-tools.linux-arm-musleabihf.node" 13 | ], 14 | "license": "MIT", 15 | "engines": { 16 | "node": ">= 10" 17 | } 18 | } -------------------------------------------------------------------------------- /BinaryOptionsToolsJs/npm/linux-arm64-gnu/README.md: -------------------------------------------------------------------------------- 1 | # `@rick-29/binary-options-tools-linux-arm64-gnu` 2 | 3 | This is the **aarch64-unknown-linux-gnu** binary for `@rick-29/binary-options-tools` 4 | -------------------------------------------------------------------------------- /BinaryOptionsToolsJs/npm/linux-arm64-gnu/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@rick-29/binary-options-tools-linux-arm64-gnu", 3 | "version": "0.0.0", 4 | "os": [ 5 | "linux" 6 | ], 7 | "cpu": [ 8 | "arm64" 9 | ], 10 | "main": "@rick-29/binary-options-tools.linux-arm64-gnu.node", 11 | "files": [ 12 | "@rick-29/binary-options-tools.linux-arm64-gnu.node" 13 | ], 14 | "license": "MIT", 15 | "engines": { 16 | "node": ">= 10" 17 | }, 18 | "libc": [ 19 | "glibc" 20 | ] 21 | } -------------------------------------------------------------------------------- /BinaryOptionsToolsJs/npm/linux-arm64-musl/README.md: -------------------------------------------------------------------------------- 1 | # `@rick-29/binary-options-tools-linux-arm64-musl` 2 | 3 | This is the **aarch64-unknown-linux-musl** binary for `@rick-29/binary-options-tools` 4 | -------------------------------------------------------------------------------- /BinaryOptionsToolsJs/npm/linux-arm64-musl/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@rick-29/binary-options-tools-linux-arm64-musl", 3 | "version": "0.0.0", 4 | "os": [ 5 | "linux" 6 | ], 7 | "cpu": [ 8 | "arm64" 9 | ], 10 | "main": "@rick-29/binary-options-tools.linux-arm64-musl.node", 11 | "files": [ 12 | "@rick-29/binary-options-tools.linux-arm64-musl.node" 13 | ], 14 | "license": "MIT", 15 | "engines": { 16 | "node": ">= 10" 17 | }, 18 | "libc": [ 19 | "musl" 20 | ] 21 | } -------------------------------------------------------------------------------- /BinaryOptionsToolsJs/npm/linux-riscv64-gnu/README.md: -------------------------------------------------------------------------------- 1 | # `@rick-29/binary-options-tools-linux-riscv64-gnu` 2 | 3 | This is the **riscv64gc-unknown-linux-gnu** binary for `@rick-29/binary-options-tools` 4 | -------------------------------------------------------------------------------- /BinaryOptionsToolsJs/npm/linux-riscv64-gnu/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@rick-29/binary-options-tools-linux-riscv64-gnu", 3 | "version": "0.0.0", 4 | "os": [ 5 | "linux" 6 | ], 7 | "cpu": [ 8 | "riscv64" 9 | ], 10 | "main": "@rick-29/binary-options-tools.linux-riscv64-gnu.node", 11 | "files": [ 12 | "@rick-29/binary-options-tools.linux-riscv64-gnu.node" 13 | ], 14 | "license": "MIT", 15 | "engines": { 16 | "node": ">= 10" 17 | }, 18 | "libc": [ 19 | "glibc" 20 | ] 21 | } -------------------------------------------------------------------------------- /BinaryOptionsToolsJs/npm/linux-x64-gnu/README.md: -------------------------------------------------------------------------------- 1 | # `@rick-29/binary-options-tools-linux-x64-gnu` 2 | 3 | This is the **x86_64-unknown-linux-gnu** binary for `@rick-29/binary-options-tools` 4 | -------------------------------------------------------------------------------- /BinaryOptionsToolsJs/npm/linux-x64-gnu/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@rick-29/binary-options-tools-linux-x64-gnu", 3 | "version": "0.0.0", 4 | "os": [ 5 | "linux" 6 | ], 7 | "cpu": [ 8 | "x64" 9 | ], 10 | "main": "@rick-29/binary-options-tools.linux-x64-gnu.node", 11 | "files": [ 12 | "@rick-29/binary-options-tools.linux-x64-gnu.node" 13 | ], 14 | "license": "MIT", 15 | "engines": { 16 | "node": ">= 10" 17 | }, 18 | "libc": [ 19 | "glibc" 20 | ] 21 | } -------------------------------------------------------------------------------- /BinaryOptionsToolsJs/npm/linux-x64-musl/README.md: -------------------------------------------------------------------------------- 1 | # `@rick-29/binary-options-tools-linux-x64-musl` 2 | 3 | This is the **x86_64-unknown-linux-musl** binary for `@rick-29/binary-options-tools` 4 | -------------------------------------------------------------------------------- /BinaryOptionsToolsJs/npm/linux-x64-musl/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@rick-29/binary-options-tools-linux-x64-musl", 3 | "version": "0.0.0", 4 | "os": [ 5 | "linux" 6 | ], 7 | "cpu": [ 8 | "x64" 9 | ], 10 | "main": "@rick-29/binary-options-tools.linux-x64-musl.node", 11 | "files": [ 12 | "@rick-29/binary-options-tools.linux-x64-musl.node" 13 | ], 14 | "license": "MIT", 15 | "engines": { 16 | "node": ">= 10" 17 | }, 18 | "libc": [ 19 | "musl" 20 | ] 21 | } -------------------------------------------------------------------------------- /BinaryOptionsToolsJs/npm/win32-arm64-msvc/README.md: -------------------------------------------------------------------------------- 1 | # `@rick-29/binary-options-tools-win32-arm64-msvc` 2 | 3 | This is the **aarch64-pc-windows-msvc** binary for `@rick-29/binary-options-tools` 4 | -------------------------------------------------------------------------------- /BinaryOptionsToolsJs/npm/win32-arm64-msvc/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@rick-29/binary-options-tools-win32-arm64-msvc", 3 | "version": "0.0.0", 4 | "os": [ 5 | "win32" 6 | ], 7 | "cpu": [ 8 | "arm64" 9 | ], 10 | "main": "@rick-29/binary-options-tools.win32-arm64-msvc.node", 11 | "files": [ 12 | "@rick-29/binary-options-tools.win32-arm64-msvc.node" 13 | ], 14 | "license": "MIT", 15 | "engines": { 16 | "node": ">= 10" 17 | } 18 | } -------------------------------------------------------------------------------- /BinaryOptionsToolsJs/npm/win32-ia32-msvc/README.md: -------------------------------------------------------------------------------- 1 | # `@rick-29/binary-options-tools-win32-ia32-msvc` 2 | 3 | This is the **i686-pc-windows-msvc** binary for `@rick-29/binary-options-tools` 4 | -------------------------------------------------------------------------------- /BinaryOptionsToolsJs/npm/win32-ia32-msvc/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@rick-29/binary-options-tools-win32-ia32-msvc", 3 | "version": "0.0.0", 4 | "os": [ 5 | "win32" 6 | ], 7 | "cpu": [ 8 | "ia32" 9 | ], 10 | "main": "@rick-29/binary-options-tools.win32-ia32-msvc.node", 11 | "files": [ 12 | "@rick-29/binary-options-tools.win32-ia32-msvc.node" 13 | ], 14 | "license": "MIT", 15 | "engines": { 16 | "node": ">= 10" 17 | } 18 | } -------------------------------------------------------------------------------- /BinaryOptionsToolsJs/npm/win32-x64-msvc/README.md: -------------------------------------------------------------------------------- 1 | # `@rick-29/binary-options-tools-win32-x64-msvc` 2 | 3 | This is the **x86_64-pc-windows-msvc** binary for `@rick-29/binary-options-tools` 4 | -------------------------------------------------------------------------------- /BinaryOptionsToolsJs/npm/win32-x64-msvc/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@rick-29/binary-options-tools-win32-x64-msvc", 3 | "version": "0.0.0", 4 | "os": [ 5 | "win32" 6 | ], 7 | "cpu": [ 8 | "x64" 9 | ], 10 | "main": "@rick-29/binary-options-tools.win32-x64-msvc.node", 11 | "files": [ 12 | "@rick-29/binary-options-tools.win32-x64-msvc.node" 13 | ], 14 | "license": "MIT", 15 | "engines": { 16 | "node": ">= 10" 17 | } 18 | } -------------------------------------------------------------------------------- /BinaryOptionsToolsJs/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@rick-29/binary-options-tools", 3 | "version": "0.1.0", 4 | "main": "index.js", 5 | "types": "index.d.ts", 6 | "napi": { 7 | "name": "binary-options-tools", 8 | "triples": { 9 | "additional": [ 10 | "aarch64-apple-darwin", 11 | "aarch64-linux-android", 12 | "aarch64-unknown-linux-gnu", 13 | "aarch64-unknown-linux-musl", 14 | "aarch64-pc-windows-msvc", 15 | "armv7-unknown-linux-gnueabihf", 16 | "armv7-unknown-linux-musleabihf", 17 | "x86_64-unknown-linux-musl", 18 | "x86_64-unknown-freebsd", 19 | "i686-pc-windows-msvc", 20 | "armv7-linux-androideabi", 21 | "universal-apple-darwin", 22 | "riscv64gc-unknown-linux-gnu" 23 | ] 24 | } 25 | }, 26 | "license": "MIT", 27 | "devDependencies": { 28 | "@napi-rs/cli": "^2.18.4", 29 | "ava": "^6.0.1" 30 | }, 31 | "ava": { 32 | "timeout": "3m" 33 | }, 34 | "engines": { 35 | "node": ">= 10" 36 | }, 37 | "scripts": { 38 | "artifacts": "napi artifacts", 39 | "build": "napi build --platform --release", 40 | "build:debug": "napi build --platform", 41 | "prepublishOnly": "napi prepublish -t npm", 42 | "test": "ava", 43 | "universal": "napi universal", 44 | "version": "napi version" 45 | }, 46 | "packageManager": "yarn@4.7.0" 47 | } 48 | -------------------------------------------------------------------------------- /BinaryOptionsToolsJs/rustfmt.toml: -------------------------------------------------------------------------------- 1 | tab_spaces = 4 2 | edition = "2021" 3 | -------------------------------------------------------------------------------- /BinaryOptionsToolsJs/src/error.rs: -------------------------------------------------------------------------------- 1 | use binary_options_tools::{ 2 | error::BinaryOptionsToolsError, pocketoption::error::PocketOptionError, 3 | }; 4 | use napi::Error; 5 | use thiserror::Error; 6 | use uuid::Uuid; 7 | 8 | #[derive(Error, Debug)] 9 | pub enum BinaryErrorJs { 10 | #[error("BinaryOptionsError, {0}")] 11 | BinaryOptionsError(#[from] BinaryOptionsToolsError), 12 | #[error("PocketOptionError, {0}")] 13 | PocketOptionError(#[from] PocketOptionError), 14 | #[error("Uninitialized, {0}")] 15 | Uninitialized(String), 16 | #[error("Error descerializing data, {0}")] 17 | DeserializingError(#[from] serde_json::Error), 18 | #[error("UUID parsing error, {0}")] 19 | UuidParsingError(#[from] uuid::Error), 20 | #[error("Trade not found, haven't found trade for id '{0}'")] 21 | TradeNotFound(Uuid), 22 | #[error("Operation not allowed")] 23 | NotAllowed(String), 24 | #[error("Invalid Regex pattern, {0}")] 25 | InvalidRegexError(#[from] regex::Error), 26 | } 27 | 28 | impl From for Error { 29 | fn from(value: BinaryErrorJs) -> Self { 30 | Error::from_reason(value.to_string()) 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /BinaryOptionsToolsJs/src/lib.rs: -------------------------------------------------------------------------------- 1 | mod pocketoption; 2 | mod runtime; 3 | mod error; 4 | mod validator; 5 | mod logs; 6 | 7 | pub use pocketoption::PocketOption; 8 | pub use validator::Validator; 9 | pub use logs::{start_tracing, LogBuilder, Logger, StreamLogsLayer, StreamLogsIterator}; 10 | -------------------------------------------------------------------------------- /BinaryOptionsToolsJs/src/runtime.rs: -------------------------------------------------------------------------------- 1 | use std::sync::Arc; 2 | use tokio::runtime::Runtime; 3 | use once_cell::sync::OnceCell; 4 | use napi::bindgen_prelude::*; 5 | 6 | static RUNTIME: OnceCell> = OnceCell::new(); 7 | 8 | pub(crate) fn get_runtime() -> Result> { 9 | let runtime = RUNTIME.get_or_try_init(|| { 10 | Ok::<_, Error>(Arc::new(Runtime::new().map_err(|err| { 11 | Error::from_reason(format!("Could not create tokio runtime. {}", err)) 12 | })?)) 13 | })?; 14 | Ok(runtime.clone()) 15 | } -------------------------------------------------------------------------------- /BinaryOptionsToolsJs/wrapper/index.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ChipaDevTeam/BinaryOptionsTools-v2/739f401208a7160a076bb2349591bc0a081f1fb1/BinaryOptionsToolsJs/wrapper/index.js -------------------------------------------------------------------------------- /BinaryOptionsToolsV2/.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | 3 | # Byte-compiled / optimized / DLL files 4 | __pycache__/ 5 | .pytest_cache/ 6 | *.py[cod] 7 | 8 | # C extensions 9 | *.so 10 | 11 | # Distribution / packaging 12 | .Python 13 | .venv/ 14 | env/ 15 | bin/ 16 | build/ 17 | develop-eggs/ 18 | dist/ 19 | eggs/ 20 | lib/ 21 | lib64/ 22 | parts/ 23 | sdist/ 24 | var/ 25 | include/ 26 | man/ 27 | venv/ 28 | *.egg-info/ 29 | .installed.cfg 30 | *.egg 31 | 32 | # Installer logs 33 | pip-log.txt 34 | pip-delete-this-directory.txt 35 | pip-selfcheck.json 36 | 37 | # Unit test / coverage reports 38 | htmlcov/ 39 | .tox/ 40 | .coverage 41 | .cache 42 | nosetests.xml 43 | coverage.xml 44 | 45 | # Translations 46 | *.mo 47 | 48 | # Mr Developer 49 | .mr.developer.cfg 50 | .project 51 | .pydevproject 52 | 53 | # Rope 54 | .ropeproject 55 | 56 | # Django stuff: 57 | *.log 58 | *.pot 59 | 60 | .DS_Store 61 | 62 | # Sphinx documentation 63 | docs/_build/ 64 | 65 | # PyCharm 66 | .idea/ 67 | 68 | # VSCode 69 | .vscode/ 70 | 71 | # Pyenv 72 | .python-version 73 | -------------------------------------------------------------------------------- /BinaryOptionsToolsV2/BinaryOptionsToolsV2/__init__.py: -------------------------------------------------------------------------------- 1 | 2 | from .BinaryOptionsToolsV2 import * # noqa: F403 3 | 4 | # optional: include the documentation from the Rust module 5 | from .BinaryOptionsToolsV2 import __doc__ # noqa: F401 6 | 7 | from .pocketoption import __all__ as __pocket_all__ 8 | from . import tracing 9 | from . import validator 10 | 11 | __all__ = __pocket_all__ + ['tracing', 'validator'] 12 | -------------------------------------------------------------------------------- /BinaryOptionsToolsV2/BinaryOptionsToolsV2/config.py: -------------------------------------------------------------------------------- 1 | from BinaryOptionsToolsV2 import PyConfig 2 | from typing import Dict, Any, List 3 | from dataclasses import dataclass 4 | 5 | import json 6 | 7 | @dataclass 8 | class Config: 9 | """ 10 | Python wrapper around PyConfig that provides additional functionality 11 | for configuration management. 12 | """ 13 | max_allowed_loops: int = 100 14 | sleep_interval: int = 100 15 | reconnect_time: int = 5 16 | connection_initialization_timeout_secs: int = 30 17 | timeout_secs: int = 30 18 | urls: List[str] = None 19 | 20 | # Extra duration, used by functions like `check_win` 21 | extra_duration: int = 5 22 | 23 | def __post_init__(self): 24 | self.urls = self.urls or [] 25 | self._pyconfig = None 26 | self._locked = False 27 | 28 | @property 29 | def pyconfig(self) -> PyConfig: 30 | """ 31 | Returns the PyConfig instance for use in Rust code. 32 | Once this is accessed, the configuration becomes locked. 33 | """ 34 | if self._pyconfig is None: 35 | self._pyconfig = PyConfig() 36 | self._update_pyconfig() 37 | self._locked = True 38 | return self._pyconfig 39 | 40 | def _update_pyconfig(self): 41 | """Updates the internal PyConfig with current values""" 42 | if self._locked: 43 | raise RuntimeError("Configuration is locked and cannot be modified after being used") 44 | 45 | if self._pyconfig is None: 46 | self._pyconfig = PyConfig() 47 | 48 | self._pyconfig.max_allowed_loops = self.max_allowed_loops 49 | self._pyconfig.sleep_interval = self.sleep_interval 50 | self._pyconfig.reconnect_time = self.reconnect_time 51 | self._pyconfig.connection_initialization_timeout_secs = self.connection_initialization_timeout_secs 52 | self._pyconfig.timeout_secs = self.timeout_secs 53 | self._pyconfig.urls = self.urls.copy() 54 | 55 | @classmethod 56 | def from_dict(cls, config_dict: Dict[str, Any]) -> 'Config': 57 | """ 58 | Creates a Config instance from a dictionary. 59 | 60 | Args: 61 | config_dict: Dictionary containing configuration values 62 | 63 | Returns: 64 | Config instance 65 | """ 66 | return cls(**{ 67 | k: v for k, v in config_dict.items() 68 | if k in Config.__dataclass_fields__ 69 | }) 70 | 71 | @classmethod 72 | def from_json(cls, json_str: str) -> 'Config': 73 | """ 74 | Creates a Config instance from a JSON string. 75 | 76 | Args: 77 | json_str: JSON string containing configuration values 78 | 79 | Returns: 80 | Config instance 81 | """ 82 | return cls.from_dict(json.loads(json_str)) 83 | 84 | def to_dict(self) -> Dict[str, Any]: 85 | """ 86 | Converts the configuration to a dictionary. 87 | 88 | Returns: 89 | Dictionary containing all configuration values 90 | """ 91 | return { 92 | 'max_allowed_loops': self.max_allowed_loops, 93 | 'sleep_interval': self.sleep_interval, 94 | 'reconnect_time': self.reconnect_time, 95 | 'connection_initialization_timeout_secs': self.connection_initialization_timeout_secs, 96 | 'timeout_secs': self.timeout_secs, 97 | 'urls': self.urls 98 | } 99 | 100 | def to_json(self) -> str: 101 | """ 102 | Converts the configuration to a JSON string. 103 | 104 | Returns: 105 | JSON string containing all configuration values 106 | """ 107 | return json.dumps(self.to_dict()) 108 | 109 | def update(self, config_dict: Dict[str, Any]) -> None: 110 | """ 111 | Updates the configuration with values from a dictionary. 112 | 113 | Args: 114 | config_dict: Dictionary containing new configuration values 115 | """ 116 | if self._locked: 117 | raise RuntimeError("Configuration is locked and cannot be modified after being used") 118 | 119 | for key, value in config_dict.items(): 120 | if hasattr(self, key): 121 | setattr(self, key, value) 122 | 123 | -------------------------------------------------------------------------------- /BinaryOptionsToolsV2/BinaryOptionsToolsV2/pocketoption/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | Module for Pocket Option related functionality. 3 | 4 | Contains asynchronous and synchronous clients, 5 | as well as specific classes for Pocket Option trading. 6 | """ 7 | 8 | __all__ = ['asyncronous', 'syncronous', 'PocketOptionAsync', 'PocketOption'] 9 | 10 | from . import asyncronous, syncronous 11 | from .asyncronous import PocketOptionAsync 12 | from .syncronous import PocketOption 13 | 14 | -------------------------------------------------------------------------------- /BinaryOptionsToolsV2/BinaryOptionsToolsV2/tracing.py: -------------------------------------------------------------------------------- 1 | import json 2 | from BinaryOptionsToolsV2 import start_tracing 3 | from BinaryOptionsToolsV2 import Logger as RustLogger 4 | from BinaryOptionsToolsV2 import LogBuilder as RustLogBuilder 5 | 6 | from datetime import timedelta 7 | 8 | class LogSubscription: 9 | def __init__(self, subscription): 10 | self.subscription = subscription 11 | 12 | def __aiter__(self): 13 | return self 14 | 15 | async def __anext__(self): 16 | return json.loads(await anext(self.subscription)) 17 | 18 | def __iter__(self): 19 | return self 20 | 21 | def __next__(self): 22 | return json.loads(next(self.subscription)) 23 | 24 | 25 | def start_logs(path: str, level: str = "DEBUG", terminal: bool = True, layers: list = None): 26 | """ 27 | Initialize logging system for the application. 28 | 29 | Args: 30 | path (str): Path where log files will be stored. 31 | level (str): Logging level (default is "DEBUG"). 32 | terminal (bool): Whether to display logs in the terminal (default is True). 33 | 34 | Returns: 35 | None 36 | 37 | Raises: 38 | Exception: If there's an error starting the logging system. 39 | """ 40 | if layers is None: 41 | layers = [] 42 | try: 43 | start_tracing(path, level, terminal, layers) 44 | except Exception as e: 45 | print(f"Error starting logs, {e}") 46 | 47 | 48 | class Logger: 49 | """ 50 | A logger class wrapping the RustLogger functionality. 51 | 52 | Attributes: 53 | logger (RustLogger): The underlying RustLogger instance. 54 | """ 55 | def __init__(self): 56 | self.logger = RustLogger() 57 | 58 | def debug(self, message): 59 | """ 60 | Log a debug message. 61 | 62 | Args: 63 | message (str): The message to log. 64 | """ 65 | self.logger.debug(str(message)) 66 | 67 | def info(self, message): 68 | """ 69 | Log an informational message. 70 | 71 | Args: 72 | message (str): The message to log. 73 | """ 74 | self.logger.info(str(message)) 75 | 76 | def warn(self, message): 77 | """ 78 | Log a warning message. 79 | 80 | Args: 81 | message (str): The message to log. 82 | """ 83 | self.logger.warn(str(message)) 84 | 85 | def error(self, message): 86 | """ 87 | Log an error message. 88 | 89 | Args: 90 | message (str): The message to log. 91 | """ 92 | self.logger.error(str(message)) 93 | 94 | 95 | class LogBuilder: 96 | """ 97 | A builder class for configuring the logs, create log layers and iterators. 98 | 99 | Attributes: 100 | builder (RustLogBuilder): The underlying RustLogBuilder instance. 101 | """ 102 | def __init__(self): 103 | self.builder = RustLogBuilder() 104 | 105 | def create_logs_iterator(self, level: str = "DEBUG", timeout: None | timedelta = None) -> LogSubscription: 106 | """ 107 | Create a new logs iterator with the specified level and timeout. 108 | 109 | Args: 110 | level (str): The logging level (default is "DEBUG"). 111 | timeout (None | timedelta): Optional timeout for the iterator. 112 | 113 | Returns: 114 | StreamLogsIterator: A new StreamLogsIterator instance that supports both asyncronous and syncronous iterators. 115 | """ 116 | return LogSubscription(self.builder.create_logs_iterator(level, timeout)) 117 | 118 | def log_file(self, path: str = "logs.log", level: str = "DEBUG"): 119 | """ 120 | Configure logging to a file. 121 | 122 | Args: 123 | path (str): The path where logs will be stored (default is "logs.log"). 124 | level (str): The minimum log level for this file handler. 125 | """ 126 | self.builder.log_file(path, level) 127 | 128 | def terminal(self, level: str = "DEBUG"): 129 | """ 130 | Configure logging to the terminal. 131 | 132 | Args: 133 | level (str): The minimum log level for this terminal handler. 134 | """ 135 | self.builder.terminal(level) 136 | 137 | def build(self): 138 | """ 139 | Build and initialize the logging configuration. This function should be called only once per execution. 140 | """ 141 | self.builder.build() 142 | 143 | -------------------------------------------------------------------------------- /BinaryOptionsToolsV2/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "BinaryOptionsToolsV2" 3 | version = "0.1.7" 4 | edition = "2021" 5 | description = "A library to connect to PocketOption using python with async and sync support." 6 | license = "BSD License (BSD)" 7 | homepage = "https://github.com/ChipaDevTeam/BinaryOptionsTools-v2" 8 | readme = "Readme.md" 9 | 10 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 11 | [lib] 12 | name = "BinaryOptionsToolsV2" 13 | crate-type = ["cdylib"] 14 | 15 | [dependencies] 16 | pyo3 = { version = "0.24.2", features = ["experimental-async", "chrono"] } 17 | pyo3-async-runtimes = { version = "0.24.0", features = ["tokio-runtime"] } 18 | 19 | binary-options-tools = { path = "../crates/binary_options_tools", version = "0.1.7" } 20 | 21 | thiserror = "2.0.12" 22 | serde = { version = "1.0.219", features = ["derive"] } 23 | serde_json = "1.0.139" 24 | uuid = "1.16.0" 25 | tracing = "0.1.41" 26 | tokio = "1.44.2" 27 | futures-util = "0.3.31" 28 | tracing-subscriber = { version = "0.3.19", features = ["env-filter"] } 29 | chrono = "0.4.41" 30 | url = "2.5.4" 31 | regex = "1.11.1" 32 | -------------------------------------------------------------------------------- /BinaryOptionsToolsV2/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM rust:latest 2 | 3 | # Install system dependencies 4 | RUN apt-get update && apt-get install -y \ 5 | curl unzip build-essential pkg-config cmake \ 6 | python3 python3-pip python3-venv \ 7 | clang git libssl-dev \ 8 | && rm -rf /var/lib/apt/lists/* 9 | 10 | # Create a virtualenv and install maturin inside 11 | ENV VENV_PATH=/opt/venv 12 | RUN python3 -m venv $VENV_PATH 13 | ENV PATH="$VENV_PATH/bin:$PATH" 14 | 15 | RUN pip install --upgrade pip && pip install maturin 16 | 17 | # Android NDK setup 18 | ENV ANDROID_NDK_VERSION=r26d 19 | ENV ANDROID_SDK_ROOT=/opt/android-sdk 20 | ENV ANDROID_NDK_HOME=$ANDROID_SDK_ROOT/ndk/$ANDROID_NDK_VERSION 21 | ENV PATH="$ANDROID_NDK_HOME/toolchains/llvm/prebuilt/linux-x86_64/bin:$PATH" 22 | 23 | RUN mkdir -p $ANDROID_SDK_ROOT/ndk && \ 24 | curl -L https://dl.google.com/android/repository/android-ndk-${ANDROID_NDK_VERSION}-linux.zip -o ndk.zip && \ 25 | unzip ndk.zip -d $ANDROID_SDK_ROOT/ndk && \ 26 | rm ndk.zip 27 | 28 | # Add Android Rust targets 29 | RUN rustup target add aarch64-linux-android 30 | 31 | COPY . . 32 | 33 | ENV CC_aarch64_linux_android=aarch64-linux-android21-clang 34 | ENV CARGO_TARGET_AARCH64_LINUX_ANDROID_LINKER=aarch64-linux-android21-clang 35 | 36 | # Build .whl using maturin 37 | CMD ["maturin", "build", "--release", "--target", "aarch64-linux-android", "--interpreter", "python3"] 38 | -------------------------------------------------------------------------------- /BinaryOptionsToolsV2/pyproject.toml: -------------------------------------------------------------------------------- 1 | [build-system] 2 | requires = ["maturin>=1.7,<2.0"] 3 | build-backend = "maturin" 4 | 5 | [project] 6 | name = "BinaryOptionsToolsV2" 7 | # requires-python = ">=3.8" 8 | classifiers = [ 9 | "Programming Language :: Rust", 10 | "Programming Language :: Python :: Implementation :: CPython", 11 | "Programming Language :: Python :: Implementation :: PyPy", 12 | ] 13 | dynamic = ["version"] 14 | 15 | 16 | [tool.maturin] 17 | features = ["pyo3/extension-module"] 18 | module-name = "BinaryOptionsToolsV2" 19 | -------------------------------------------------------------------------------- /BinaryOptionsToolsV2/src/config.rs: -------------------------------------------------------------------------------- 1 | use binary_options_tools::{error::BinaryOptionsToolsError, pocketoption::parser::message::WebSocketMessage}; 2 | use pyo3::prelude::*; 3 | use std::collections::HashSet; 4 | use std::time::Duration; 5 | use url::Url; 6 | use binary_options_tools::reimports::ConfigBuilder; 7 | use binary_options_tools::pocketoption::types::data::PocketData; 8 | 9 | use crate::error::BinaryResultPy; 10 | 11 | #[pyclass] 12 | #[derive(Clone, Default)] 13 | pub struct PyConfig { 14 | #[pyo3(get, set)] 15 | pub max_allowed_loops: u32, 16 | #[pyo3(get, set)] 17 | pub sleep_interval: u64, 18 | #[pyo3(get, set)] 19 | pub reconnect_time: u64, 20 | #[pyo3(get, set)] 21 | pub connection_initialization_timeout_secs: u64, 22 | #[pyo3(get, set)] 23 | pub timeout_secs: u64, 24 | #[pyo3(get, set)] 25 | pub urls: Vec, 26 | } 27 | 28 | #[pymethods] 29 | impl PyConfig { 30 | #[new] 31 | pub fn new() -> Self { 32 | Self { 33 | max_allowed_loops: 100, 34 | sleep_interval: 100, 35 | reconnect_time: 5, 36 | connection_initialization_timeout_secs: 30, 37 | timeout_secs: 30, 38 | urls: Vec::new(), 39 | } 40 | } 41 | 42 | } 43 | 44 | impl PyConfig { 45 | pub fn build(&self) -> BinaryResultPy> { 46 | let urls: Result, url::ParseError> = self 47 | .urls 48 | .iter() 49 | .map(|url| Url::parse(url)) 50 | .collect(); 51 | 52 | let config = ConfigBuilder::new() 53 | .max_allowed_loops(self.max_allowed_loops) 54 | .sleep_interval(self.sleep_interval) 55 | .reconnect_time(self.reconnect_time) 56 | .timeout(Duration::from_secs(self.timeout_secs)) 57 | .default_connection_url(HashSet::from_iter(urls.map_err(|e| { 58 | BinaryOptionsToolsError::from(e) 59 | })?)); 60 | Ok(config) 61 | } 62 | 63 | } -------------------------------------------------------------------------------- /BinaryOptionsToolsV2/src/error.rs: -------------------------------------------------------------------------------- 1 | use binary_options_tools::{error::BinaryOptionsToolsError, pocketoption::error::PocketOptionError}; 2 | use pyo3::{exceptions::PyValueError, PyErr}; 3 | use thiserror::Error; 4 | use uuid::Uuid; 5 | 6 | #[derive(Error, Debug)] 7 | pub enum BinaryErrorPy { 8 | #[error("BinaryOptionsError, {0}")] 9 | BinaryOptionsError(#[from] BinaryOptionsToolsError), 10 | #[error("PocketOptionError, {0}")] 11 | PocketOptionError(#[from] PocketOptionError), 12 | #[error("Uninitialized, {0}")] 13 | Uninitialized(String), 14 | #[error("Error descerializing data, {0}")] 15 | DeserializingError(#[from] serde_json::Error), 16 | #[error("UUID parsing error, {0}")] 17 | UuidParsingError(#[from] uuid::Error), 18 | #[error("Trade not found, haven't found trade for id '{0}'")] 19 | TradeNotFound(Uuid), 20 | #[error("Operation not allowed")] 21 | NotAllowed(String), 22 | #[error("Invalid Regex pattern, {0}")] 23 | InvalidRegexError(#[from] regex::Error) 24 | } 25 | 26 | impl From for PyErr { 27 | fn from(value: BinaryErrorPy) -> Self { 28 | PyValueError::new_err(value.to_string()) 29 | } 30 | } 31 | 32 | pub type BinaryResultPy = Result; 33 | -------------------------------------------------------------------------------- /BinaryOptionsToolsV2/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![allow(non_snake_case)] 2 | 3 | mod error; 4 | mod logs; 5 | mod pocketoption; 6 | mod runtime; 7 | mod stream; 8 | mod validator; 9 | mod config; 10 | 11 | use config::PyConfig; 12 | use logs::{start_tracing, LogBuilder, Logger, StreamLogsIterator, StreamLogsLayer}; 13 | use pocketoption::{RawPocketOption, RawStreamIterator, StreamIterator}; 14 | use pyo3::prelude::*; 15 | use validator::RawValidator; 16 | 17 | #[pymodule] 18 | #[pyo3(name = "BinaryOptionsToolsV2")] 19 | fn BinaryOptionsTools(m: &Bound<'_, PyModule>) -> PyResult<()> { 20 | m.add_class::()?; 21 | m.add_class::()?; 22 | m.add_class::()?; 23 | m.add_class::()?; 24 | m.add_class::()?; 25 | m.add_class::()?; 26 | m.add_class::()?; 27 | m.add_class::()?; 28 | m.add_class::()?; 29 | 30 | m.add_function(wrap_pyfunction!(start_tracing, m)?)?; 31 | Ok(()) 32 | } 33 | -------------------------------------------------------------------------------- /BinaryOptionsToolsV2/src/runtime.rs: -------------------------------------------------------------------------------- 1 | use std::sync::Arc; 2 | 3 | use pyo3::exceptions::PyValueError; 4 | use pyo3::prelude::*; 5 | use pyo3::sync::GILOnceCell; 6 | use tokio::runtime::Runtime; 7 | 8 | static RUNTIME: GILOnceCell> = GILOnceCell::new(); 9 | 10 | /// Get the tokio runtime for sync requests 11 | pub(crate) fn get_runtime(py: Python<'_>) -> PyResult> { 12 | let runtime = RUNTIME.get_or_try_init(py, || { 13 | Ok::<_, PyErr>(Arc::new(Runtime::new().map_err(|err| { 14 | PyValueError::new_err(format!("Could not create tokio runtime. {}", err)) 15 | })?)) 16 | })?; 17 | Ok(runtime.clone()) 18 | } 19 | -------------------------------------------------------------------------------- /BinaryOptionsToolsV2/src/stream.rs: -------------------------------------------------------------------------------- 1 | use std::sync::Arc; 2 | 3 | use futures_util::{ 4 | stream::{BoxStream, Fuse}, 5 | StreamExt, 6 | }; 7 | use pyo3::{ 8 | exceptions::{PyStopAsyncIteration, PyStopIteration}, 9 | PyResult, 10 | }; 11 | use tokio::sync::Mutex; 12 | 13 | pub type PyStream = Fuse>>; 14 | 15 | pub async fn next_stream(stream: Arc>>, sync: bool) -> PyResult 16 | where 17 | E: std::error::Error, 18 | { 19 | let mut stream = stream.lock().await; 20 | match stream.next().await { 21 | Some(item) => match item { 22 | Ok(itm) => Ok(itm), 23 | Err(e) => { 24 | println!("Error: {:?}", e); 25 | match sync { 26 | true => Err(PyStopIteration::new_err(e.to_string())), 27 | false => Err(PyStopAsyncIteration::new_err(e.to_string())), 28 | } 29 | } 30 | }, 31 | None => match sync { 32 | true => Err(PyStopIteration::new_err("Stream exhausted")), 33 | false => Err(PyStopAsyncIteration::new_err("Stream exhausted")), 34 | }, 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /BinaryOptionsToolsV2/tests/test.py: -------------------------------------------------------------------------------- 1 | import asyncio 2 | # import pandas as pd # type: ignore 3 | # import json 4 | 5 | # import BinaryOptionsToolsV2 6 | # from BinaryOptionsToolsV2 import connect 7 | 8 | # print(BinaryOptionsToolsV2) 9 | from BinaryOptionsToolsV2.BinaryOptionsToolsV2.pocketoption.asyncronous import PocketOptionAsync 10 | 11 | # async def main(ssid): 12 | # api = await async_connect(ssid) 13 | # await asyncio.sleep(10) 14 | # payout = await api.payout() 15 | # candles = await api.history("EURUSD_otc", 7200) 16 | # trade = await api.buy("EURUSD_otc", 1, 5) 17 | # print(f"Payout: {payout}") 18 | # print(f"Candles: {candles}") 19 | # print(f"Trade: {trade}") 20 | # df = pd.DataFrame.from_dict(candles) 21 | # df.to_csv("candles_eurusd_otc.csv") 22 | async def main(ssid): 23 | # Testing the new iterator 24 | api = PocketOptionAsync(ssid) 25 | await asyncio.sleep(5) 26 | stream = await api.subscribe_symbol("EURUSD_otc") 27 | async for item in stream: 28 | print(item["time"], item["open"]) 29 | 30 | 31 | if __name__ == "__main__": 32 | ssid = input("Write your ssid: ") 33 | asyncio.run(main(ssid)) 34 | 35 | -------------------------------------------------------------------------------- /BinaryOptionsToolsV2/tests/test_sync.py: -------------------------------------------------------------------------------- 1 | from BinaryOptionsToolsV2.BinaryOptionsToolsV2.pocketoption.syncronous import PocketOption 2 | import time 3 | 4 | def main(ssid): 5 | api = PocketOption(ssid) 6 | time.sleep(5) 7 | iterator = api.subscribe_symbol("EURUSD_otc") 8 | for item in iterator: 9 | print(item) 10 | 11 | 12 | if __name__ == "__main__": 13 | ssid = input("Write your ssid: ") 14 | main(ssid) -------------------------------------------------------------------------------- /BinaryOptionsToolsV2/uv.lock: -------------------------------------------------------------------------------- 1 | version = 1 2 | requires-python = ">=3.10" 3 | 4 | [[distribution]] 5 | name = "binaryoptionstoolsv2" 6 | version = "0.1.3" 7 | source = { editable = "." } 8 | -------------------------------------------------------------------------------- /CI.yml: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ChipaDevTeam/BinaryOptionsTools-v2/739f401208a7160a076bb2349591bc0a081f1fb1/CI.yml -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2025 Chipa 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | if you are looking to build a bot, let us build it for you! check [Our shop](https://chipa.tech/shop/) 2 | ## Support us 3 | join PocketOption with our affiliate link: [https://pocket-friends.com/r/u9klnwxgcc](https://pocket-friends.com/r/u9klnwxgcc)
4 | donate in paypal: [Paypal.me](https://paypal.me/ChipaCL?country.x=CL&locale.x=en_US)
5 | help us in patreon: [Patreon](https://patreon.com/VigoDEV?utm_medium=unknown&utm_source=join_link&utm_campaign=creatorshare_creator&utm_content=copyLink)
6 | 👉 [Join us on Discord](https://discord.gg/p7YyFqSmAz) 7 | # BinaryOptionsTools 8 | Don't know programming and you are looking for a bot? [click here to get our development services!](https://chipa.tech/shop/) 9 | **Check [here](https://github.com/ChipaDevTeam/BinaryOptionsTools-v2/tree/5ef8aa83bcf3f9b8a55f0d9d5e69a1a48397ed7f) to check the repo at the time of the release** 10 | **BinaryOptionsTools** is a powerful suite of tools designed to enhance your binary options trading experience. Whether you're looking for analysis, strategy optimization, or execution tools, this project provides a variety of solutions to help you make informed trading decisions. 11 | 12 | # Features 13 | Currently we only support **Pocket Option** (quick trading) with the following features (for real and demo): 14 | * Place trades for any asset 15 | * Check trade results 16 | * Get account balance 17 | * Get the payout of each asset 18 | * Get a list with the opened and closed trades with all of the trades data 19 | * Get candle data for a specific asset 20 | * Subscribe to an asset to get realtime data 21 | 22 | # Python 23 | For the full python documentation check [here](https://github.com/ChipaDevTeam/BinaryOptionsTools-v2/blob/master/BinaryOptionsToolsV2/Readme.md). 24 | To install it use pip: 25 | ``` 26 | pip install binaryoptionstoolsv2==0.1.6a3 27 | ``` 28 | 29 | # Rust 30 | For the full rust documentation check [here](https://github.com/ChipaDevTeam/BinaryOptionsTools-v2/tree/crates/core/Readme.md) 31 | # Todo 32 | * *Pocket Option*: Add support for pending trades 33 | * *BinaryOptionsToolsV2*: Add support for **rust** (done) 34 | * *BinaryOptionsToolsV2*: Add support for other trading platforms like Expert Options 35 | 36 | # Examples 37 | You can find the examples for all the features available of the library in the [examples](https://github.com/ChipaDevTeam/BinaryOptionsTools-v2/tree/master/examples) directory. 38 | 39 | # Info 40 | Our goal is to provide access to connect to important **Binary Options Trading** platforms programatically in multiple programming languages. 41 | Currently we support the following languages: 42 | * Python 43 | * Rust 44 | 45 | And the following trading platforms: 46 | * Pocket Options 47 | 48 | We plan on supporting other programming languages and trading platforms in the future. 49 | -------------------------------------------------------------------------------- /crates/binary_options_tools/.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | .qodo 3 | Cargo.lock -------------------------------------------------------------------------------- /crates/binary_options_tools/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "binary-options-tools" 3 | version = "0.1.7" 4 | edition = "2024" 5 | repository = "https://github.com/ChipaDevTeam/BinaryOptionsTools-v2" 6 | readme = "README.md" 7 | description = "`binary-options-tools` crate and the python library `BinaryOptionsToolsV2`." 8 | license = "MIT" 9 | 10 | # [workspace] 11 | # members = [ 12 | # "../macros", "../core" 13 | # ] 14 | 15 | 16 | [dependencies] 17 | binary-options-tools-core = { path = "../core", version = "0.1.5" } 18 | binary-options-tools-macros = { path = "../macros", version = "0.1.1" } 19 | 20 | anyhow = "1.0.98" 21 | async-channel = "2.3.1" 22 | async-trait = "0.1.85" 23 | chrono = { version = "0.4.39", features = ["serde"] } 24 | futures-util = "0.3.31" 25 | native-tls = "0.2.12" 26 | php_serde = "0.6.0" 27 | rand = "0.9.1" 28 | reqwest = "0.12.15" 29 | serde = { version = "1.0.219", features = ["derive"] } 30 | serde_json = "1.0.140" 31 | thiserror = "2.0.12" 32 | tokio = { version = "1.44.2", features = ["full"] } 33 | tracing = "0.1.41" 34 | # url = { version = "2.5.4", features = ["serde"] } 35 | uuid = { version = "1.16.0", features = ["serde"] } 36 | url = "2.5.4" 37 | serde-enum-str = "0.4.0" 38 | -------------------------------------------------------------------------------- /crates/binary_options_tools/Readme.md: -------------------------------------------------------------------------------- 1 | # Binary Options Tools (Rust) 2 | 3 | [![Crates.io](https://img.shields.io/crates/v/binary_options_tools.svg)](https://crates.io/crates/binary_options_tools) 4 | [![Docs.rs](https://docs.rs/binary_options_tools/badge.svg)](https://docs.rs/binary_options_tools) 5 | 6 | 7 | A Rust crate providing tools to interact programmatically with various binary options trading platforms. 8 | 9 | ## Overview 10 | 11 | This crate aims to provide a unified and robust interface for developers looking to connect to and automate interactions with binary options trading platforms using Rust. Whether you're building trading bots, analysis tools, or integrating trading capabilities into larger applications, `binary_options_tools` strives to offer the necessary building blocks. 12 | 13 | The core library is written in Rust for performance and safety, and it serves as the foundation for potential bindings or wrappers in other programming languages. 14 | 15 | ## Installation 16 | 17 | Add the crate to your `Cargo.toml` dependencies: 18 | 19 | ```toml 20 | [dependencies] 21 | binary_options_tools = "0.1.7" 22 | ``` -------------------------------------------------------------------------------- /crates/binary_options_tools/src/lib.rs: -------------------------------------------------------------------------------- 1 | pub mod pocketoption; 2 | pub mod reimports; 3 | 4 | pub mod stream { 5 | pub use binary_options_tools_core::general::stream::RecieverStream; 6 | pub use binary_options_tools_core::utils::tracing::stream_logs_layer; 7 | } 8 | 9 | pub mod error { 10 | pub use binary_options_tools_core::error::{BinaryOptionsResult, BinaryOptionsToolsError}; 11 | } 12 | 13 | #[cfg(test)] 14 | mod tests { 15 | use std::time::Duration; 16 | 17 | use serde::{Deserialize, Serialize}; 18 | use tokio::time::sleep; 19 | use tracing::debug; 20 | 21 | use binary_options_tools_core::utils::tracing::start_tracing; 22 | use binary_options_tools_macros::{deserialize, serialize, timeout}; 23 | #[derive(Serialize, Deserialize, Debug, PartialEq, Eq)] 24 | struct Test { 25 | name: String, 26 | } 27 | 28 | #[test] 29 | fn test_deserialize_macro() { 30 | let test = Test { 31 | name: "Test".to_string(), 32 | }; 33 | let test_str = serialize!(&test).unwrap(); 34 | let test2 = deserialize!(Test, &test_str).unwrap(); 35 | assert_eq!(test, test2) 36 | } 37 | 38 | struct Tester; 39 | 40 | #[tokio::test] 41 | async fn test_timeout_macro() -> anyhow::Result<()> { 42 | start_tracing(true).unwrap(); 43 | 44 | #[timeout(1, tracing(level = "info", skip(_tester)))] 45 | async fn this_is_a_test(_tester: Tester) -> anyhow::Result<()> { 46 | debug!("Test"); 47 | sleep(Duration::from_secs(0)).await; 48 | Ok(()) 49 | } 50 | 51 | this_is_a_test(Tester).await 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /crates/binary_options_tools/src/pocketoption/error.rs: -------------------------------------------------------------------------------- 1 | use std::error::Error; 2 | use std::string::FromUtf8Error; 3 | 4 | use super::types::order::PocketMessageFail; 5 | use super::{parser::message::WebSocketMessage, types::info::MessageInfo}; 6 | use binary_options_tools_core::error::BinaryOptionsToolsError; 7 | use thiserror::Error; 8 | // use tokio_tungstenite::tungstenite::Error as TungsteniteError; 9 | // use tokio_tungstenite::tungstenite::{http, Message}; 10 | 11 | #[derive(Error, Debug)] 12 | pub enum PocketOptionError { 13 | #[error("BinaryOptionsToolsError, {0}")] 14 | BinaryOptionsToolsError(#[from] BinaryOptionsToolsError), 15 | #[error("Failed to parse SSID: {0}")] 16 | SsidParsingError(String), 17 | #[error("Failed to parse data: {0}")] 18 | GeneralParsingError(String), 19 | // #[error("Error making http request: {0}")] 20 | // HTTPError(#[from] http::Error), 21 | #[error("TLS Certificate error, {0}")] 22 | TLSError(#[from] native_tls::Error), 23 | // #[error("Failed to connect to websocket server: {0}")] 24 | // WebsocketConnectionError(#[from] TungsteniteError), 25 | #[error("Failed to connect to websocket server: {0}")] 26 | WebsocketRecievingConnectionError(String), 27 | #[error("Websocket connection was closed by the server, {0}")] 28 | WebsocketConnectionClosed(String), 29 | #[error("Failed to connect to websocket server, {0}")] 30 | WebsocketConnectionAttempFailed(String), 31 | #[error("Failed to connect to websocket server after multiple attempts, {0}")] 32 | WebsocketMultipleAttemptsConnectionError(String), 33 | #[error("Failed to parse recieved data to Message: {0}")] 34 | WebSocketMessageParsingError(#[from] serde_json::Error), 35 | #[error("Failed to process recieved Message: {0}")] 36 | WebSocketMessageProcessingError(#[from] anyhow::Error), 37 | #[error("Failed to convert bytes to string, {0}")] 38 | WebSocketMessageByteSerializationError(#[from] FromUtf8Error), 39 | // #[error("Failed to send message to websocket sender, {0}")] 40 | // MessageSendingError(#[from] async_channel::SendError), 41 | #[error("Failed to send message to websocket sender, {0}")] 42 | ThreadMessageSendingErrorMPCS(#[from] async_channel::SendError), 43 | #[error("Failed to recieve message from separate thread, {0}")] 44 | OneShotRecieverError(#[from] tokio::sync::oneshot::error::RecvError), 45 | #[error("Failed to send message to websocket sender, {0}")] 46 | ThreadMessageSendingError(#[from] WebSocketMessage), 47 | #[error("Failed to make request, {0}")] 48 | RequestError(#[from] reqwest::Error), 49 | #[error("Unexpected error, recieved incorrect WebSocketMessage type, recieved {0}")] 50 | UnexpectedIncorrectWebSocketMessage(#[from] MessageInfo), 51 | #[error("If you are having this error please contact the developpers, {0}")] 52 | UnreachableError(String), 53 | #[error("Unallowed operation, {0}")] 54 | Unallowed(String), 55 | #[error("Error sending request, {0}")] 56 | WebsocketMessageSendingError(#[from] PocketMessageFail), 57 | #[error("Expected the data to be non-empty for type '{0}'")] 58 | EmptyArrayError(String), 59 | #[error("General compiling error: {0}")] 60 | CompilingError(#[from] Box), 61 | } 62 | 63 | pub type PocketResult = Result; 64 | 65 | impl Error for WebSocketMessage {} 66 | impl Error for MessageInfo {} 67 | impl Error for PocketMessageFail {} 68 | 69 | impl From for BinaryOptionsToolsError { 70 | fn from(value: PocketOptionError) -> Self { 71 | BinaryOptionsToolsError::BinaryOptionsTradingError { 72 | platform: "Pocket Option".to_string(), 73 | error: value.to_string(), 74 | } 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /crates/binary_options_tools/src/pocketoption/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod error; 2 | pub mod parser; 3 | pub mod pocket_client; 4 | pub mod types; 5 | pub mod utils; 6 | pub mod validators; 7 | pub mod ws; 8 | 9 | // pub use super::pocketoption::ws::basic::WebSocketClient; 10 | -------------------------------------------------------------------------------- /crates/binary_options_tools/src/pocketoption/parser/basic.rs: -------------------------------------------------------------------------------- 1 | use chrono::{DateTime, Utc}; 2 | use serde::{Deserialize, Serialize}; 3 | 4 | use crate::pocketoption::{ 5 | error::PocketResult, types::update::float_time, utils::basic::get_index, 6 | }; 7 | 8 | #[derive(Debug, Deserialize)] 9 | #[allow(unused)] 10 | pub struct UpdateStream { 11 | active: String, 12 | #[serde(with = "float_time")] 13 | time: DateTime, 14 | value: f64, 15 | } 16 | 17 | #[derive(Debug, Deserialize)] 18 | #[serde(rename_all = "lowercase")] 19 | enum AssetType { 20 | Stock, 21 | Currency, 22 | Commodity, 23 | Cryptocurrency, 24 | Index, 25 | } 26 | 27 | #[derive(Debug, Serialize, Deserialize, Clone)] 28 | pub struct LoadHistoryPeriod { 29 | pub asset: String, 30 | pub period: i64, 31 | pub time: i64, 32 | pub index: u64, 33 | pub offset: i64, 34 | } 35 | 36 | impl LoadHistoryPeriod { 37 | pub fn new(asset: impl ToString, time: i64, period: i64, offset: i64) -> PocketResult { 38 | Ok(LoadHistoryPeriod { 39 | asset: asset.to_string(), 40 | period, 41 | time, 42 | index: get_index()?, 43 | offset, 44 | }) 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /crates/binary_options_tools/src/pocketoption/parser/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod basic; 2 | pub mod message; 3 | -------------------------------------------------------------------------------- /crates/binary_options_tools/src/pocketoption/types/base.rs: -------------------------------------------------------------------------------- 1 | use core::fmt; 2 | 3 | use binary_options_tools_core::general::traits::RawMessage; 4 | use serde::{Deserialize, Serialize}; 5 | 6 | #[derive(Debug, Deserialize, Serialize, Clone)] 7 | #[serde(rename_all = "camelCase")] 8 | pub struct ChangeSymbol { 9 | pub asset: String, 10 | pub period: i64, 11 | } 12 | 13 | #[derive(Debug, Deserialize, Serialize, Clone)] 14 | pub struct SubscribeSymbol(String); 15 | 16 | impl ChangeSymbol { 17 | pub fn new(asset: String, period: i64) -> Self { 18 | Self { asset, period } 19 | } 20 | } 21 | 22 | #[derive(Debug, Clone)] 23 | pub struct RawWebsocketMessage { 24 | value: String, 25 | } 26 | 27 | impl fmt::Display for RawWebsocketMessage { 28 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 29 | self.value.fmt(f) 30 | } 31 | } 32 | 33 | impl Serialize for RawWebsocketMessage { 34 | fn serialize(&self, serializer: S) -> Result 35 | where 36 | S: serde::Serializer, 37 | { 38 | serializer.serialize_str(&self.value) 39 | } 40 | } 41 | 42 | impl<'de> Deserialize<'de> for RawWebsocketMessage { 43 | fn deserialize(deserializer: D) -> Result 44 | where 45 | D: serde::Deserializer<'de>, 46 | { 47 | String::deserialize(deserializer).map(|s| Self { value: s }) 48 | } 49 | } 50 | 51 | impl From for RawWebsocketMessage { 52 | fn from(value: String) -> Self { 53 | Self { value } 54 | } 55 | } 56 | 57 | impl From<&str> for RawWebsocketMessage { 58 | fn from(value: &str) -> Self { 59 | Self { value: value.to_string() } 60 | } 61 | } 62 | 63 | impl RawMessage for RawWebsocketMessage {} 64 | -------------------------------------------------------------------------------- /crates/binary_options_tools/src/pocketoption/types/callback.rs: -------------------------------------------------------------------------------- 1 | use std::time::Duration; 2 | 3 | use async_trait::async_trait; 4 | use futures_util::future::try_join; 5 | use tokio::time::sleep; 6 | use tracing::{debug, info, instrument}; 7 | 8 | use crate::pocketoption::{ 9 | error::PocketOptionError, parser::message::WebSocketMessage, types::info::MessageInfo, 10 | validators::history_validator, 11 | }; 12 | use binary_options_tools_core::{ 13 | error::{BinaryOptionsResult, BinaryOptionsToolsError}, 14 | general::{config::Config, send::SenderMessage, traits::WCallback, types::Data}, 15 | }; 16 | 17 | use super::{base::ChangeSymbol, data::PocketData, order::SuccessCloseOrder}; 18 | 19 | #[derive(Clone)] 20 | pub struct PocketCallback; 21 | 22 | impl PocketCallback { 23 | async fn update_assets( 24 | data: &Data, 25 | sender: &SenderMessage, 26 | config: &Config, 27 | ) -> BinaryOptionsResult<()> { 28 | for asset in data.stream_assets().await { 29 | sleep(Duration::from_secs(1)).await; 30 | let history = ChangeSymbol::new(asset.to_string(), 3600); 31 | let res = sender 32 | .send_message_with_timout( 33 | config.get_timeout()?, 34 | "SubscribeSymbolCallback", 35 | data, 36 | WebSocketMessage::ChangeSymbol(history), 37 | MessageInfo::UpdateHistoryNew, 38 | Box::new(history_validator(asset.to_string(), 3600)), 39 | ) 40 | .await?; 41 | if let WebSocketMessage::UpdateHistoryNew(_) = res { 42 | debug!("Sent 'ChangeSymbol' for asset: {asset}"); 43 | } else { 44 | return Err(PocketOptionError::UnexpectedIncorrectWebSocketMessage( 45 | res.information(), 46 | ) 47 | .into()); 48 | } 49 | } 50 | Ok(()) 51 | } 52 | 53 | async fn update_check_results( 54 | data: &Data, 55 | ) -> BinaryOptionsResult<()> { 56 | if let Some(sender) = data.sender(MessageInfo::SuccesscloseOrder).await { 57 | let deals = data.get_closed_deals().await; 58 | if !deals.is_empty() { 59 | info!(target: "CheckResultCallback", "Sending closed orders data after disconnection"); 60 | let close_order = SuccessCloseOrder { profit: 0.0, deals }; 61 | sender 62 | .send(WebSocketMessage::SuccesscloseOrder(close_order)) 63 | .await 64 | .map_err(|e| { 65 | BinaryOptionsToolsError::GeneralMessageSendingError(e.to_string()) 66 | })?; 67 | } 68 | } 69 | Ok(()) 70 | } 71 | } 72 | #[async_trait] 73 | impl WCallback for PocketCallback { 74 | type T = PocketData; 75 | type Transfer = WebSocketMessage; 76 | type U = (); 77 | 78 | #[instrument(skip(self, data, sender, config))] 79 | async fn call( 80 | &self, 81 | data: Data, 82 | sender: &SenderMessage, 83 | config: &Config, 84 | ) -> BinaryOptionsResult<()> { 85 | // let sender = sender.clone(); 86 | let update_assets_future = Self::update_assets(&data, sender, &config); 87 | let update_check_results_future = Self::update_check_results(&data); 88 | try_join(update_assets_future, update_check_results_future).await?; 89 | Ok(()) 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /crates/binary_options_tools/src/pocketoption/types/info.rs: -------------------------------------------------------------------------------- 1 | use serde_enum_str::{Deserialize_enum_str, Serialize_enum_str}; 2 | 3 | use binary_options_tools_core::general::traits::MessageInformation; 4 | 5 | use super::base::RawWebsocketMessage; 6 | 7 | #[derive(Debug, Deserialize_enum_str, Serialize_enum_str, Clone, PartialEq, Eq, Hash)] 8 | #[serde(rename_all = "camelCase")] 9 | pub enum MessageInfo { 10 | OpenOrder, 11 | UpdateStream, 12 | UpdateHistoryNew, 13 | UpdateAssets, 14 | UpdateBalance, 15 | SuccesscloseOrder, 16 | Auth, 17 | ChangeSymbol, 18 | SuccessupdateBalance, 19 | SuccessupdatePending, 20 | Successauth, 21 | UpdateOpenedDeals, 22 | UpdateClosedDeals, 23 | SuccessopenOrder, 24 | // UpdateCharts, 25 | 26 | SubscribeSymbol, 27 | LoadHistoryPeriod, 28 | FailopenOrder, 29 | GetCandles, 30 | OpenPendingOrder, 31 | SuccessopenPendingOrder, 32 | FailopenPendingOrder, 33 | None, 34 | 35 | #[serde(other)] 36 | Raw(String), 37 | } 38 | 39 | impl MessageInfo { 40 | pub fn get_raw(&self) -> Option { 41 | if let Self::Raw(raw) = self { 42 | Some(RawWebsocketMessage::from(raw.to_owned())) 43 | } else { 44 | None 45 | } 46 | } 47 | } 48 | 49 | impl MessageInformation for MessageInfo {} 50 | 51 | #[cfg(test)] 52 | mod tests { 53 | use std::error::Error; 54 | 55 | use super::*; 56 | 57 | #[test] 58 | fn test_parse_message_info() -> Result<(), Box> { 59 | dbg!(serde_json::to_string(&MessageInfo::OpenOrder)?); 60 | Ok(()) 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /crates/binary_options_tools/src/pocketoption/types/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod base; 2 | pub mod callback; 3 | pub mod data; 4 | pub mod info; 5 | pub mod order; 6 | pub mod success; 7 | pub mod update; 8 | -------------------------------------------------------------------------------- /crates/binary_options_tools/src/pocketoption/types/success.rs: -------------------------------------------------------------------------------- 1 | use serde::{Deserialize, Serialize}; 2 | 3 | #[derive(Debug, Deserialize, Serialize, Clone)] 4 | #[serde(rename_all = "camelCase")] 5 | #[serde(untagged)] 6 | pub enum SuccessAuth { 7 | Real(RealAuth), 8 | Demo(DemoAuth), 9 | } 10 | 11 | #[derive(Debug, Deserialize, Serialize, Clone)] 12 | #[serde(rename_all = "camelCase")] 13 | pub struct DemoAuth { 14 | id: String, 15 | } 16 | 17 | #[derive(Debug, Deserialize, Serialize, Clone)] 18 | #[serde(rename_all = "camelCase")] 19 | pub struct RealAuth { 20 | server_name: String, 21 | } 22 | -------------------------------------------------------------------------------- /crates/binary_options_tools/src/pocketoption/utils/basic.rs: -------------------------------------------------------------------------------- 1 | use chrono::{Duration, Utc}; 2 | use rand::{Rng, rng}; 3 | 4 | use crate::pocketoption::error::{PocketOptionError, PocketResult}; 5 | 6 | pub fn get_index() -> PocketResult { 7 | // rand = str(random.randint(10, 99)) 8 | // cu = int(time.time()) 9 | // t = str(cu + (2 * 60 * 60)) 10 | // index = int(t + rand) 11 | let mut rng = rng(); 12 | 13 | let rand = rng.random_range(10..99); 14 | let time = (Utc::now() + Duration::hours(2)).timestamp(); 15 | format!("{}{}", time, rand) 16 | .parse::() 17 | .map_err(|e| PocketOptionError::GeneralParsingError(e.to_string())) 18 | } 19 | 20 | pub fn is_otc(symbol: &str) -> bool { 21 | symbol.ends_with("otc") 22 | } 23 | -------------------------------------------------------------------------------- /crates/binary_options_tools/src/pocketoption/utils/connect.rs: -------------------------------------------------------------------------------- 1 | use binary_options_tools_core::{ 2 | error::BinaryOptionsToolsError, 3 | reimports::{ 4 | Connector, MaybeTlsStream, Request, WebSocketStream, connect_async_tls_with_config, 5 | generate_key, 6 | }, 7 | }; 8 | use tokio::net::TcpStream; 9 | use url::Url; 10 | 11 | use crate::pocketoption::{ 12 | error::{PocketOptionError, PocketResult}, 13 | ws::ssid::Ssid, 14 | }; 15 | 16 | pub async fn try_connect( 17 | ssid: Ssid, 18 | url: String, 19 | ) -> PocketResult>> { 20 | let tls_connector = native_tls::TlsConnector::builder().build()?; 21 | 22 | let connector = Connector::NativeTls(tls_connector); 23 | 24 | let user_agent = ssid.user_agent(); 25 | let t_url = Url::parse(&url) 26 | .map_err(|e| PocketOptionError::GeneralParsingError(format!("Error getting host, {e}")))?; 27 | let host = t_url 28 | .host_str() 29 | .ok_or(PocketOptionError::GeneralParsingError( 30 | "Host not found".into(), 31 | ))?; 32 | let request = Request::builder() 33 | .uri(t_url.to_string()) 34 | .header("Origin", "https://pocketoption.com") 35 | .header("Cache-Control", "no-cache") 36 | .header("User-Agent", user_agent) 37 | .header("Upgrade", "websocket") 38 | .header("Connection", "upgrade") 39 | .header("Sec-Websocket-Key", generate_key()) 40 | .header("Sec-Websocket-Version", "13") 41 | .header("Host", host) 42 | .body(()) 43 | .map_err(BinaryOptionsToolsError::from)?; 44 | 45 | let (ws, _) = connect_async_tls_with_config(request, None, false, Some(connector)) 46 | .await 47 | .map_err(BinaryOptionsToolsError::from)?; 48 | Ok(ws) 49 | } 50 | -------------------------------------------------------------------------------- /crates/binary_options_tools/src/pocketoption/utils/location.rs: -------------------------------------------------------------------------------- 1 | use serde_json::Value; 2 | 3 | use crate::pocketoption::error::PocketResult; 4 | 5 | pub async fn get_user_location(ip_address: &str) -> PocketResult<(f64, f64)> { 6 | let response = reqwest::get(format!("http://ip-api.com/json/{}", ip_address)).await?; 7 | let json: Value = response.json().await?; 8 | 9 | let lat = json["lat"].as_f64().unwrap(); 10 | let lon = json["lon"].as_f64().unwrap(); 11 | 12 | Ok((lat, lon)) 13 | } 14 | 15 | pub fn calculate_distance(lat1: f64, lon1: f64, lat2: f64, lon2: f64) -> f64 { 16 | // Haversine formula to calculate distance between two coordinates 17 | const R: f64 = 6371.0; // Radius of Earth in kilometers 18 | 19 | let dlat = (lat2 - lat1).to_radians(); 20 | let dlon = (lon2 - lon1).to_radians(); 21 | 22 | let lat1 = lat1.to_radians(); 23 | let lat2 = lat2.to_radians(); 24 | 25 | let a = dlat.sin().powi(2) + lat1.cos() * lat2.cos() * dlon.sin().powi(2); 26 | let c = 2.0 * a.sqrt().asin(); 27 | 28 | R * c 29 | } 30 | 31 | pub async fn get_public_ip() -> PocketResult { 32 | let response = reqwest::get("https://api.ipify.org?format=json").await?; 33 | let json: serde_json::Value = response.json().await?; 34 | Ok(json["ip"].as_str().unwrap().to_string()) 35 | } 36 | -------------------------------------------------------------------------------- /crates/binary_options_tools/src/pocketoption/utils/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod basic; 2 | pub mod connect; 3 | pub mod location; 4 | -------------------------------------------------------------------------------- /crates/binary_options_tools/src/pocketoption/validators.rs: -------------------------------------------------------------------------------- 1 | use uuid::Uuid; 2 | 3 | use super::parser::message::WebSocketMessage; 4 | 5 | pub fn order_validator(order_index: u64) -> impl Fn(&WebSocketMessage) -> bool + Send + Sync { 6 | move |message| { 7 | if let WebSocketMessage::SuccessopenOrder(order) = message { 8 | if order.request_id.is_some_and(|id| id == order_index) { 9 | return true; 10 | } 11 | } 12 | false 13 | } 14 | } 15 | 16 | pub fn candle_validator(index: u64) -> impl Fn(&WebSocketMessage) -> bool + Send + Sync { 17 | move |message| { 18 | if let WebSocketMessage::LoadHistoryPeriod(history) = message { 19 | if history 20 | .index 21 | .div_euclid(100) 22 | .abs_diff(index.div_euclid(100)) 23 | <= 1 24 | { 25 | return true; 26 | } 27 | } 28 | false 29 | } 30 | } 31 | 32 | pub fn order_result_validator(order_id: Uuid) -> impl Fn(&WebSocketMessage) -> bool + Send + Sync { 33 | move |message| { 34 | if let WebSocketMessage::SuccesscloseOrder(orders) = message { 35 | if orders.deals.iter().any(|o| o == &order_id) { 36 | return true; 37 | } 38 | } 39 | false 40 | } 41 | } 42 | 43 | pub fn history_validator( 44 | asset: String, 45 | period: i64, 46 | ) -> impl Fn(&WebSocketMessage) -> bool + Send + Sync { 47 | move |message| { 48 | if let WebSocketMessage::UpdateHistoryNew(history) = message { 49 | if history.asset == asset && history.period == period { 50 | return true; 51 | } 52 | } 53 | false 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /crates/binary_options_tools/src/pocketoption/ws/connect.rs: -------------------------------------------------------------------------------- 1 | use std::time::Duration; 2 | 3 | use async_channel::{Sender, bounded}; 4 | use async_trait::async_trait; 5 | use futures_util::future::join_all; 6 | use tokio::net::TcpStream; 7 | use tracing::info; 8 | use url::Url; 9 | 10 | use crate::pocketoption::{error::PocketOptionError, utils::connect::try_connect}; 11 | use binary_options_tools_core::{ 12 | error::{BinaryOptionsResult, BinaryOptionsToolsError}, 13 | general::{ 14 | config::Config, 15 | traits::{Connect, DataHandler, InnerConfig, MessageTransfer}, 16 | }, 17 | reimports::{MaybeTlsStream, WebSocketStream}, 18 | }; 19 | 20 | use super::ssid::Ssid; 21 | 22 | #[derive(Clone)] 23 | pub struct PocketConnect; 24 | 25 | #[async_trait] 26 | impl Connect for PocketConnect { 27 | type Creds = Ssid; 28 | 29 | async fn connect( 30 | &self, 31 | creds: Self::Creds, 32 | config: &Config, 33 | ) -> BinaryOptionsResult>> { 34 | async fn send_ws( 35 | creds: Ssid, 36 | url: String, 37 | sender: Sender<(WebSocketStream>, String)>, 38 | ) -> BinaryOptionsResult<()> { 39 | info!(target: "TryConnect", "Trying to connecto to {}", url); 40 | if let Ok(connect) = try_connect(creds, url.clone()).await { 41 | info!(target: "SuccessConnect", "Succesfully connected to {}", url); 42 | sender.send((connect, url.clone())).await.map_err(|e| { 43 | BinaryOptionsToolsError::GeneralMessageSendingError(e.to_string()) 44 | })?; 45 | } 46 | tokio::time::sleep(Duration::from_millis(500)).await; 47 | Err(BinaryOptionsToolsError::WebsocketRecievingConnectionError( 48 | url, 49 | )) 50 | } 51 | let (sender, reciever) = bounded(1); // It should stop after recieving only one message 52 | let default_urls = config.get_default_connection_url()?; 53 | let default_connections = default_urls 54 | .iter() 55 | .map(|url| tokio::spawn(send_ws(creds.clone(), url.to_string(), sender.clone()))); 56 | tokio::select! { 57 | res = reciever.recv() => return Ok(res.map(|(r, _)| r)?), 58 | _ = join_all(default_connections) => {} 59 | } 60 | let urls = creds.servers().await?; 61 | let connections = urls 62 | .iter() 63 | .map(|url| tokio::spawn(send_ws(creds.clone(), url.to_owned(), sender.clone()))); 64 | tokio::select! { 65 | res = reciever.recv() => match res { 66 | Ok((res, url)) => { 67 | config.add_default_connection_url(Url::parse(&url)?)?; 68 | Ok(res) 69 | }, 70 | Err(e) => Err(e.into()) 71 | }, 72 | _ = join_all(connections) => Err( 73 | PocketOptionError::WebsocketMultipleAttemptsConnectionError(format!( 74 | "Couldn't connect to server after {} attempts.", 75 | urls.len() 76 | )) 77 | .into(), 78 | ) 79 | } 80 | } 81 | // async fn connect( 82 | // &self, 83 | // creds: Self::Creds, 84 | // config: &Config, 85 | // ) -> BinaryOptionsResult>> { 86 | // for url in config.get_default_connection_url()? { 87 | // info!("Using default connection url..."); 88 | // if let Ok(connect) = try_connect(creds.clone(), url.to_string()).await { 89 | // return Ok(connect); 90 | // } 91 | // } 92 | // let urls = creds.servers().await?; 93 | // let mut error = None; 94 | // for url in urls.clone() { 95 | // match try_connect(creds.clone(), url).await { 96 | // Ok(connect) => return Ok(connect), 97 | // Err(e) => { 98 | // warn!("Failed to connect to server, {e}"); 99 | // error = Some(e); 100 | // } 101 | // } 102 | // } 103 | // if let Some(error) = error { 104 | // Err(error.into()) 105 | // } else { 106 | // Err( 107 | // PocketOptionError::WebsocketMultipleAttemptsConnectionError(format!( 108 | // "Couldn't connect to server after {} attempts.", 109 | // urls.len() 110 | // )) 111 | // .into(), 112 | // ) 113 | // } 114 | // } 115 | } 116 | -------------------------------------------------------------------------------- /crates/binary_options_tools/src/pocketoption/ws/listener.rs: -------------------------------------------------------------------------------- 1 | use async_trait::async_trait; 2 | use serde_json::Value; 3 | 4 | use binary_options_tools_core::{ 5 | error::{BinaryOptionsResult, BinaryOptionsToolsError}, 6 | general::{ 7 | send::SenderMessage, 8 | traits::{MessageHandler, MessageTransfer}, 9 | types::MessageType, 10 | }, 11 | reimports::Message, 12 | }; 13 | 14 | use crate::pocketoption::{ 15 | error::PocketResult, 16 | parser::message::WebSocketMessage, 17 | types::{base::ChangeSymbol, info::MessageInfo}, 18 | }; 19 | 20 | use super::ssid::Ssid; 21 | 22 | #[derive(Clone)] 23 | pub struct Handler { 24 | ssid: Ssid, 25 | } 26 | 27 | impl Handler { 28 | pub fn new(ssid: Ssid) -> Self { 29 | Self { ssid } 30 | } 31 | 32 | pub fn handle_binary_msg( 33 | &self, 34 | bytes: &Vec, 35 | previous: &Option, 36 | ) -> PocketResult { 37 | let msg = String::from_utf8(bytes.to_owned())?; 38 | let message = match previous { 39 | Some(previous) => WebSocketMessage::parse_with_context(msg, previous), 40 | None => { 41 | let message: WebSocketMessage = serde_json::from_str(&msg)?; 42 | message 43 | } 44 | }; 45 | 46 | Ok(message) 47 | } 48 | 49 | pub async fn handle_text_msg( 50 | &self, 51 | text: &str, 52 | sender: &SenderMessage, 53 | ) -> BinaryOptionsResult> { 54 | match text { 55 | _ if text.starts_with('0') && text.contains("sid") => { 56 | sender.priority_send(Message::text("40")).await?; 57 | } 58 | _ if text.starts_with("40") && text.contains("sid") => { 59 | sender 60 | .priority_send(Message::text(self.ssid.to_string())) 61 | .await?; 62 | } 63 | _ if text == "2" => { 64 | sender.priority_send(Message::text("3")).await?; 65 | // write.send(Message::text("3".into())).await.unwrap(); 66 | // write.flush().await.unwrap(); 67 | } 68 | _ if text.starts_with("451-") => { 69 | let msg = text.strip_prefix("451-").unwrap(); 70 | let (info, _): (MessageInfo, Value) = 71 | serde_json::from_str(msg).map_err(BinaryOptionsToolsError::from)?; 72 | if let MessageInfo::Raw(_) = info { 73 | return Ok(Some(MessageInfo::Raw(format!("451-{}", msg)))) 74 | } 75 | if info == MessageInfo::UpdateClosedDeals { 76 | sender 77 | .priority_send(Message::text( 78 | WebSocketMessage::ChangeSymbol(ChangeSymbol { 79 | asset: "AUDNZD_otc".into(), 80 | period: 60, 81 | }) 82 | .to_string(), 83 | )) 84 | .await?; 85 | } 86 | return Ok(Some(info)); 87 | } 88 | _ => {} 89 | } 90 | 91 | Ok(None) 92 | } 93 | } 94 | 95 | #[async_trait] 96 | impl MessageHandler for Handler { 97 | type Transfer = WebSocketMessage; 98 | 99 | async fn process_message( 100 | &self, 101 | message: &Message, 102 | previous: &Option, 103 | sender: &SenderMessage, 104 | ) -> BinaryOptionsResult<(Option>, bool)> { 105 | match message { 106 | Message::Binary(binary) => { 107 | let msg = self.handle_binary_msg(&binary.to_vec(), previous)?; 108 | if let Some(raw) = msg.get_raw() { 109 | return Ok((Some(MessageType::Raw(raw)), false)) 110 | } 111 | return Ok((Some(MessageType::Transfer(msg)), false)); 112 | } 113 | Message::Text(text) => { 114 | let res = self 115 | .handle_text_msg::(text.as_ref(), sender) 116 | .await?; 117 | return Ok((res.map(|r| { 118 | if let Some(raw) = r.get_raw() { 119 | MessageType::Raw(raw) 120 | } else { 121 | MessageType::Info(r) 122 | } 123 | }), false)); 124 | } 125 | Message::Frame(_) => {} // TODO: 126 | Message::Ping(b) => { 127 | sender.priority_send(Message::Pong(b.to_owned())).await?; 128 | } // TODO: 129 | Message::Pong(_) => {} // TODO: 130 | Message::Close(_) => return Ok((None, true)), 131 | } 132 | Ok((None, false)) 133 | } 134 | } 135 | -------------------------------------------------------------------------------- /crates/binary_options_tools/src/pocketoption/ws/mod.rs: -------------------------------------------------------------------------------- 1 | // pub mod api; 2 | // pub mod basic; 3 | pub mod connect; 4 | pub mod listener; 5 | pub mod regions; 6 | pub mod ssid; 7 | pub mod stream; 8 | -------------------------------------------------------------------------------- /crates/binary_options_tools/src/pocketoption/ws/regions.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "url": "wss://demo-api-eu.po.market/socket.io/?EIO=4&transport=websocket", 4 | "name": "DEMO", 5 | "latitude": 50.0, 6 | "longitude": 10.0, 7 | "demo": true 8 | }, 9 | { 10 | "url": "wss://api-eu.po.market/socket.io/?EIO=4&transport=websocket", 11 | "name": "EUROPE", 12 | "latitude": 50.0, 13 | "longitude": 10.0, 14 | "demo": false 15 | }, 16 | { 17 | "url": "wss://api-sc.po.market/socket.io/?EIO=4&transport=websocket", 18 | "name": "SEYCHELLES", 19 | "latitude": -4.0, 20 | "longitude": 55.0, 21 | "demo": false 22 | }, 23 | { 24 | "url": "wss://api-hk.po.market/socket.io/?EIO=4&transport=websocket", 25 | "name": "HONG_KONG", 26 | "latitude": 22.0, 27 | "longitude": 114.0, 28 | "demo": false 29 | }, 30 | { 31 | "url": "wss://api-spb.po.market/socket.io/?EIO=4&transport=websocket", 32 | "name": "RUSSIA_SPB", 33 | "latitude": 60.0, 34 | "longitude": 30.0, 35 | "demo": false 36 | }, 37 | { 38 | "url": "wss://api-fr2.po.market/socket.io/?EIO=4&transport=websocket", 39 | "name": "FRANCE_2", 40 | "latitude": 46.0, 41 | "longitude": 2.0, 42 | "demo": false 43 | }, 44 | { 45 | "url": "wss://api-us4.po.market/socket.io/?EIO=4&transport=websocket", 46 | "name": "US_WEST_4", 47 | "latitude": 37.0, 48 | "longitude": -122.0, 49 | "demo": false 50 | }, 51 | { 52 | "url": "wss://api-us3.po.market/socket.io/?EIO=4&transport=websocket", 53 | "name": "US_WEST_3", 54 | "latitude": 34.0, 55 | "longitude": -118.0, 56 | "demo": false 57 | }, 58 | { 59 | "url": "wss://api-us2.po.market/socket.io/?EIO=4&transport=websocket", 60 | "name": "US_WEST_2", 61 | "latitude": 39.0, 62 | "longitude": -77.0, 63 | "demo": false 64 | }, 65 | { 66 | "url": "wss://api-us-north.po.market/socket.io/?EIO=4&transport=websocket", 67 | "name": "US_NORTH", 68 | "latitude": 42.0, 69 | "longitude": -71.0, 70 | "demo": false 71 | }, 72 | { 73 | "url": "wss://api-msk.po.market/socket.io/?EIO=4&transport=websocket", 74 | "name": "RUSSIA_MOSCOW", 75 | "latitude": 55.0, 76 | "longitude": 37.0, 77 | "demo": false 78 | }, 79 | { 80 | "url": "wss://api-l.po.market/socket.io/?EIO=4&transport=websocket", 81 | "name": "LATIN_AMERICA", 82 | "latitude": 0.0, 83 | "longitude": -45.0, 84 | "demo": false 85 | }, 86 | { 87 | "url": "wss://api-in.po.market/socket.io/?EIO=4&transport=websocket", 88 | "name": "INDIA", 89 | "latitude": 20.0, 90 | "longitude": 77.0, 91 | "demo": false 92 | }, 93 | { 94 | "url": "wss://api-fr.po.market/socket.io/?EIO=4&transport=websocket", 95 | "name": "FRANCE", 96 | "latitude": 46.0, 97 | "longitude": 2.0, 98 | "demo": false 99 | }, 100 | { 101 | "url": "wss://api-fin.po.market/socket.io/?EIO=4&transport=websocket", 102 | "name": "FINLAND", 103 | "latitude": 62.0, 104 | "longitude": 27.0, 105 | "demo": false 106 | }, 107 | { 108 | "url": "wss://api-c.po.market/socket.io/?EIO=4&transport=websocket", 109 | "name": "CHINA", 110 | "latitude": 35.0, 111 | "longitude": 105.0, 112 | "demo": false 113 | }, 114 | { 115 | "url": "wss://api-asia.po.market/socket.io/?EIO=4&transport=websocket", 116 | "name": "ASIA", 117 | "latitude": 10.0, 118 | "longitude": 100.0, 119 | "demo": false 120 | } 121 | ] -------------------------------------------------------------------------------- /crates/binary_options_tools/src/pocketoption/ws/regions.rs: -------------------------------------------------------------------------------- 1 | use binary_options_tools_macros::RegionImpl; 2 | 3 | use crate::pocketoption::{ 4 | error::PocketResult, 5 | utils::location::{calculate_distance, get_public_ip, get_user_location}, 6 | }; 7 | 8 | #[derive(RegionImpl)] 9 | #[region(path = "src/pocketoption/ws/regions.json")] 10 | pub struct Regions; 11 | 12 | impl Regions { 13 | async fn get_closest_server(&self, ip_address: &str) -> PocketResult<(&str, f64)> { 14 | let user_location = get_user_location(ip_address).await?; 15 | 16 | let mut closest = ("", f64::INFINITY); 17 | Self::regions().iter().for_each(|(server, lat, lon)| { 18 | let distance = calculate_distance(user_location.0, user_location.1, *lat, *lon); 19 | if distance < closest.1 { 20 | closest = (*server, distance) 21 | } 22 | }); 23 | Ok(closest) 24 | } 25 | 26 | async fn sort_servers(&self, ip_address: &str) -> PocketResult> { 27 | let user_location = get_user_location(ip_address).await?; 28 | let mut distances = Self::regions() 29 | .iter() 30 | .map(|(server, lat, lon)| { 31 | ( 32 | *server, 33 | calculate_distance(user_location.0, user_location.1, *lat, *lon), 34 | ) 35 | }) 36 | .collect::>(); 37 | distances.sort_by(|(_, a), (_, b)| b.total_cmp(a)); 38 | Ok(distances.into_iter().map(|(s, _)| s).collect()) 39 | } 40 | 41 | pub async fn get_server(&self) -> PocketResult<&str> { 42 | let ip = get_public_ip().await?; 43 | let server = self.get_closest_server(&ip).await?; 44 | Ok(server.0) 45 | } 46 | 47 | pub async fn get_servers(&self) -> PocketResult> { 48 | let ip = get_public_ip().await?; 49 | self.sort_servers(&ip).await 50 | } 51 | } 52 | 53 | #[cfg(test)] 54 | mod tests { 55 | use super::*; 56 | 57 | #[tokio::test] 58 | async fn test_get_closest_server() -> anyhow::Result<()> { 59 | // let ip = get_public_ip().await?; 60 | let server = Regions.get_server().await?; 61 | dbg!(server); 62 | Ok(()) 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /crates/binary_options_tools/src/reimports.rs: -------------------------------------------------------------------------------- 1 | pub use binary_options_tools_core::general::traits::ValidatorTrait; 2 | pub use binary_options_tools_core::general::stream::FilteredRecieverStream; 3 | pub use binary_options_tools_core::general::config::ConfigBuilder; 4 | 5 | pub use binary_options_tools_macros::Config; 6 | -------------------------------------------------------------------------------- /crates/binary_options_tools/tests/assets.txt: -------------------------------------------------------------------------------- 1 | #AAPL 2 | #AAPL_otc 3 | #AXP 4 | #AXP_otc 5 | #BA 6 | #BA_otc 7 | #CSCO 8 | #CSCO_otc 9 | #FB 10 | #FB_otc 11 | #INTC 12 | #INTC_otc 13 | #JNJ 14 | #JNJ_otc 15 | #JPM 16 | #MCD 17 | #MCD_otc 18 | #MSFT 19 | #MSFT_otc 20 | #PFE 21 | #PFE_otc 22 | #TSLA 23 | #TSLA_otc 24 | #XOM 25 | #XOM_otc 26 | 100GBP 27 | 100GBP_otc 28 | ADA-USD_otc 29 | AEDCNY_otc 30 | AEX25 31 | AMZN_otc 32 | AUDCAD 33 | AUDCAD_otc 34 | AUDCHF 35 | AUDCHF_otc 36 | AUDJPY 37 | AUDJPY_otc 38 | AUDNZD_otc 39 | AUDUSD 40 | AUDUSD_otc 41 | AUS200 42 | AUS200_otc 43 | AVAX_otc 44 | BABA 45 | BABA_otc 46 | BCHEUR 47 | BCHGBP 48 | BCHJPY 49 | BHDCNY_otc 50 | BITB_otc 51 | BNB-USD_otc 52 | BTCGBP 53 | BTCJPY 54 | BTCUSD 55 | BTCUSD_otc 56 | CAC40 57 | CADCHF 58 | CADCHF_otc 59 | CADJPY 60 | CADJPY_otc 61 | CHFJPY 62 | CHFJPY_otc 63 | CHFNOK_otc 64 | CITI 65 | CITI_otc 66 | D30EUR 67 | D30EUR_otc 68 | DASH_USD 69 | DJI30 70 | DJI30_otc 71 | DOGE_otc 72 | DOTUSD_otc 73 | E35EUR 74 | E35EUR_otc 75 | E50EUR 76 | E50EUR_otc 77 | ETHUSD 78 | ETHUSD_otc 79 | EURAUD 80 | EURCAD 81 | EURCHF 82 | EURCHF_otc 83 | EURGBP 84 | EURGBP_otc 85 | EURHUF_otc 86 | EURJPY 87 | EURJPY_otc 88 | EURNZD_otc 89 | EURRUB_otc 90 | EURTRY_otc 91 | EURUSD 92 | EURUSD_otc 93 | F40EUR 94 | F40EUR_otc 95 | FDX_otc 96 | GBPAUD 97 | GBPAUD_otc 98 | GBPCAD 99 | GBPCHF 100 | GBPJPY 101 | GBPJPY_otc 102 | GBPUSD 103 | GBPUSD_otc 104 | H33HKD 105 | IRRUSD_otc 106 | JODCNY_otc 107 | JPN225 108 | JPN225_otc 109 | LBPUSD_otc 110 | LINK_otc 111 | LNKUSD 112 | LTCUSD_otc 113 | MADUSD_otc 114 | MATIC_otc 115 | NASUSD 116 | NASUSD_otc 117 | NFLX 118 | NFLX_otc 119 | NZDJPY_otc 120 | NZDUSD_otc 121 | OMRCNY_otc 122 | QARCNY_otc 123 | SARCNY_otc 124 | SMI20 125 | SOL-USD_otc 126 | SP500 127 | SP500_otc 128 | SYPUSD_otc 129 | TNDUSD_otc 130 | TON-USD_otc 131 | TRX-USD_otc 132 | TWITTER 133 | TWITTER_otc 134 | UKBrent 135 | UKBrent_otc 136 | USCrude 137 | USCrude_otc 138 | USDARS_otc 139 | USDBDT_otc 140 | USDBRL_otc 141 | USDCAD 142 | USDCAD_otc 143 | USDCHF 144 | USDCHF_otc 145 | USDCLP_otc 146 | USDCNH_otc 147 | USDCOP_otc 148 | USDDZD_otc 149 | USDEGP_otc 150 | USDIDR_otc 151 | USDINR_otc 152 | USDJPY 153 | USDJPY_otc 154 | USDMXN_otc 155 | USDMYR_otc 156 | USDPHP_otc 157 | USDPKR_otc 158 | USDRUB_otc 159 | USDSGD_otc 160 | USDTHB_otc 161 | USDVND_otc 162 | VISA_otc 163 | XAGEUR 164 | XAGUSD 165 | XAGUSD_otc 166 | XAUEUR 167 | XAUUSD 168 | XAUUSD_otc 169 | XNGUSD 170 | XNGUSD_otc 171 | XPDUSD 172 | XPDUSD_otc 173 | XPTUSD 174 | XPTUSD_otc 175 | XRPUSD_otc 176 | YERUSD_otc 177 | -------------------------------------------------------------------------------- /crates/binary_options_tools/tests/fail_open_pending_order.json: -------------------------------------------------------------------------------- 1 | 2 | { 3 | "data": { 4 | "data": { 5 | "ticket": "74e3e01d-78f9-4619-82ce-f6cf9e51673a", 6 | "openType": 0, 7 | "amount": 1, 8 | "uid": 87742848, 9 | "isDemo": 1, 10 | "symbol": "EURUSD_otc", 11 | "openTime": "2024-12-31 20:24:24", 12 | "openPrice": 0, 13 | "timeframe": 60, 14 | "minPayout": 60, 15 | "command": 0, 16 | "dateCreated": "2024-12-31 20:32:00" 17 | }, 18 | "error": "OPEN_TIME" 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /crates/binary_options_tools/tests/fail_open_pending_order2.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": { 3 | "data": { 4 | "ticket": "4f8ae136-8a92-4232-9b0e-28f94db50fbe", 5 | "openType": 0, 6 | "amount": 1, 7 | "uid": 87742848, 8 | "isDemo": 1, 9 | "symbol": "EURUSD_otc", 10 | "openTime": "2024-12-31 20:34:27", 11 | "openPrice": 0, 12 | "timeframe": 60, 13 | "minPayout": 60, 14 | "command": 0, 15 | "dateCreated": "2024-12-31 20:32:33" 16 | }, 17 | "error": "MaxDemoTrades", 18 | "amount": 10, 19 | "asset": "EURUSD_otc" 20 | } 21 | } -------------------------------------------------------------------------------- /crates/binary_options_tools/tests/success_open_order.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": "27897152-8199-4d2f-946a-59de837b85d6", 3 | "openTime": "2024-12-04 23:58:48", 4 | "closeTime": "2024-12-04 23:59:48", 5 | "openTimestamp": 1733356728, 6 | "closeTimestamp": 1733356788, 7 | "uid": 87742848, 8 | "isDemo": 1, 9 | "amount": 1, 10 | "profit": 0.92, 11 | "percentProfit": 92, 12 | "percentLoss": 100, 13 | "openPrice": 37.81209, 14 | "copyTicket": "", 15 | "closePrice": 0, 16 | "command": 0, 17 | "asset": "EURTRY_otc", 18 | "requestId": 19656019, 19 | "openMs": 601, 20 | "optionType": 100, 21 | "isCopySignal": false, 22 | "currency": "USD" 23 | } 24 | -------------------------------------------------------------------------------- /crates/binary_options_tools/tests/success_open_pending_order.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": { 3 | "ticket": "a0523357-2582-4b55-a92f-e0da117e80a7", 4 | "openType": 0, 5 | "amount": 1, 6 | "symbol": "EURUSD_otc", 7 | "openTime": "2024-12-31 20:12:19", 8 | "openPrice": 0, 9 | "timeframe": 60, 10 | "minPayout": 60, 11 | "command": 0, 12 | "dateCreated": "2024-12-31 20:10:24", 13 | "id": 1943327 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /crates/binary_options_tools/tests/success_update_pending.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "ticket": "0a251728-4c1c-4b37-b770-0b8d9fffa941", 4 | "openType": 1, 5 | "amount": 1, 6 | "uid": 90000798, 7 | "isDemo": 1, 8 | "symbol": "#AXP_otc", 9 | "openTime": "0000-00-00 00:00:00", 10 | "openPrice": 171.125, 11 | "timeframe": 60, 12 | "minPayout": 60, 13 | "command": 1, 14 | "dateCreated": "2024-12-14 02:27:46", 15 | "id": 1791437 16 | }, 17 | { 18 | "ticket": "9b39a0a2-6f50-48bc-a752-0aa888f88302", 19 | "openType": 0, 20 | "amount": 1, 21 | "uid": 90000798, 22 | "isDemo": 1, 23 | "symbol": "#AXP_otc", 24 | "openTime": "2024-12-14 02:32:59", 25 | "openPrice": 0, 26 | "timeframe": 60, 27 | "minPayout": 60, 28 | "command": 0, 29 | "dateCreated": "2024-12-14 02:31:02", 30 | "id": 1791452 31 | }, 32 | { 33 | "ticket": "12e7a8f6-c902-4512-aabc-28acffed494c", 34 | "openType": 0, 35 | "amount": 1, 36 | "uid": 90000798, 37 | "isDemo": 1, 38 | "symbol": "#AXP_otc", 39 | "openTime": "2024-12-14 02:32:59", 40 | "openPrice": 0, 41 | "timeframe": 60, 42 | "minPayout": 60, 43 | "command": 1, 44 | "dateCreated": "2024-12-14 02:31:07", 45 | "id": 1791453 46 | }, 47 | { 48 | "ticket": "a6a43aad-cb27-409a-b0e9-63e82a316d7c", 49 | "openType": 0, 50 | "amount": 1, 51 | "uid": 90000798, 52 | "isDemo": 1, 53 | "symbol": "#AXP_otc", 54 | "openTime": "2024-12-14 02:32:59", 55 | "openPrice": 0, 56 | "timeframe": 60, 57 | "minPayout": 60, 58 | "command": 1, 59 | "dateCreated": "2024-12-14 02:31:11", 60 | "id": 1791454 61 | } 62 | ] -------------------------------------------------------------------------------- /crates/binary_options_tools/tests/test.json: -------------------------------------------------------------------------------- 1 | { 2 | "session": "a:4:{s:10:\"session_id\";s:32:\"ae3aa847add89c341ec18d8ae5bf8527\";s:10:\"ip_address\";s:15:\"191.113.157.139\";s:10:\"user_agent\";s:120:\"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36 OPR/114.\";s:13:\"last_activity\";i:1732926685;}31666d2dc07fdd866353937b97901e2b", 3 | "isDemo": 0, 4 | "uid": 87742848, 5 | "platform": 2 6 | } 7 | -------------------------------------------------------------------------------- /crates/binary_options_tools/tests/test_close_order.txt: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "id": "a2303df9-7c27-4cdb-99ff-a18783a70bf4", 4 | "openTime": "2024-12-02 00:13:19", 5 | "closeTime": "2024-12-02 00:14:19", 6 | "openTimestamp": 1733098399, 7 | "closeTimestamp": 1733098459, 8 | "refundTime": null, 9 | "refundTimestamp": null, 10 | "uid": 87742848, 11 | "amount": 1, 12 | "profit": 0.92, 13 | "percentProfit": 92, 14 | "percentLoss": 100, 15 | "openPrice": 37.8223, 16 | "closePrice": 37.82237, 17 | "command": 0, 18 | "asset": "EURTRY_otc", 19 | "isDemo": 1, 20 | "copyTicket": "", 21 | "openMs": 151, 22 | "closeMs": 0, 23 | "optionType": 100, 24 | "isRollover": false, 25 | "isCopySignal": false, 26 | "isAI": false, 27 | "currency": "USD", 28 | "amountUsd": 1, 29 | "amountUSD": 1 30 | }, 31 | { 32 | "id": "66a25c66-e79d-4212-b65e-f226ee08136f", 33 | "openTime": "2024-12-02 00:22:57", 34 | "closeTime": "2024-12-02 00:23:57", 35 | "openTimestamp": 1733098977, 36 | "closeTimestamp": 1733099037, 37 | "uid": 87742848, 38 | "amount": 1, 39 | "profit": 0, 40 | "percentProfit": 92, 41 | "percentLoss": 100, 42 | "openPrice": 37.82207, 43 | "closePrice": 37.82207, 44 | "command": 0, 45 | "asset": "EURTRY_otc", 46 | "isDemo": 1, 47 | "copyTicket": "", 48 | "closeMs": 0, 49 | "optionType": 100, 50 | "openMs": 171, 51 | "currency": "USD", 52 | "amountUSD": 1 53 | } 54 | ] 55 | -------------------------------------------------------------------------------- /crates/binary_options_tools/tests/test_demo.json: -------------------------------------------------------------------------------- 1 | { 2 | "session": "looc69ct294h546o368s0lct7d", 3 | "isDemo": 1, 4 | "uid": 87742848, 5 | "platform": 2 6 | } 7 | -------------------------------------------------------------------------------- /crates/binary_options_tools/tests/update_close_order.json: -------------------------------------------------------------------------------- 1 | { 2 | "profit": 0, 3 | "deals": [ 4 | { 5 | "id": "15d72f39-a382-4bd2-a8ea-40743874b044", 6 | "openTime": "2024-12-03 03:18:47", 7 | "closeTime": "2024-12-03 03:19:47", 8 | "openTimestamp": 1733195927, 9 | "closeTimestamp": 1733195987, 10 | "uid": 87742848, 11 | "amount": 1, 12 | "profit": -1, 13 | "percentProfit": 92, 14 | "percentLoss": 100, 15 | "openPrice": 172.436, 16 | "closePrice": 172.448, 17 | "command": 1, 18 | "asset": "#AXP_otc", 19 | "isDemo": 1, 20 | "copyTicket": "", 21 | "closeMs": 35, 22 | "optionType": 100, 23 | "openMs": 480, 24 | "currency": "USD", 25 | "amountUSD": 1 26 | }, 27 | { 28 | "id": "9457e22e-ec1b-4b90-acd0-11bf896c6aa7", 29 | "openTime": "2024-12-03 03:18:47", 30 | "closeTime": "2024-12-03 03:19:47", 31 | "openTimestamp": 1733195927, 32 | "closeTimestamp": 1733195987, 33 | "uid": 87742848, 34 | "amount": 1, 35 | "profit": -1, 36 | "percentProfit": 92, 37 | "percentLoss": 100, 38 | "openPrice": 172.436, 39 | "closePrice": 172.448, 40 | "command": 1, 41 | "asset": "#AXP_otc", 42 | "isDemo": 1, 43 | "copyTicket": "", 44 | "closeMs": 35, 45 | "optionType": 100, 46 | "openMs": 480, 47 | "currency": "USD", 48 | "amountUSD": 1 49 | }, 50 | { 51 | "id": "66306742-8884-49cb-83d6-7608d611d2a4", 52 | "openTime": "2024-12-03 03:18:47", 53 | "closeTime": "2024-12-03 03:19:47", 54 | "openTimestamp": 1733195927, 55 | "closeTimestamp": 1733195987, 56 | "uid": 87742848, 57 | "amount": 1, 58 | "profit": -1, 59 | "percentProfit": 92, 60 | "percentLoss": 100, 61 | "openPrice": 172.435, 62 | "closePrice": 172.448, 63 | "command": 1, 64 | "asset": "#AXP_otc", 65 | "isDemo": 1, 66 | "copyTicket": "", 67 | "closeMs": 35, 68 | "optionType": 100, 69 | "openMs": 980, 70 | "currency": "USD", 71 | "amountUSD": 1 72 | }, 73 | { 74 | "id": "ee01752c-6b37-4616-bf6d-b9de2441fac0", 75 | "openTime": "2024-12-03 03:18:47", 76 | "closeTime": "2024-12-03 03:19:47", 77 | "openTimestamp": 1733195927, 78 | "closeTimestamp": 1733195987, 79 | "uid": 87742848, 80 | "amount": 1, 81 | "profit": -1, 82 | "percentProfit": 92, 83 | "percentLoss": 100, 84 | "openPrice": 172.435, 85 | "closePrice": 172.448, 86 | "command": 1, 87 | "asset": "#AXP_otc", 88 | "isDemo": 1, 89 | "copyTicket": "", 90 | "closeMs": 35, 91 | "optionType": 100, 92 | "openMs": 980, 93 | "currency": "USD", 94 | "amountUSD": 1 95 | }, 96 | { 97 | "id": "d29470d1-2665-43be-86bb-9e2e60e9a563", 98 | "openTime": "2024-12-03 03:18:47", 99 | "closeTime": "2024-12-03 03:19:47", 100 | "openTimestamp": 1733195927, 101 | "closeTimestamp": 1733195987, 102 | "uid": 87742848, 103 | "amount": 1, 104 | "profit": -1, 105 | "percentProfit": 92, 106 | "percentLoss": 100, 107 | "openPrice": 172.435, 108 | "closePrice": 172.448, 109 | "command": 1, 110 | "asset": "#AXP_otc", 111 | "isDemo": 1, 112 | "copyTicket": "", 113 | "closeMs": 35, 114 | "optionType": 100, 115 | "openMs": 980, 116 | "currency": "USD", 117 | "amountUSD": 1 118 | } 119 | ] 120 | } 121 | -------------------------------------------------------------------------------- /crates/binary_options_tools/tests/update_opened_deals.txt: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "id": "2f561661-334c-4de3-920f-f095c7b1193f", 4 | "openTime": "2024-12-05 00:52:26", 5 | "closeTime": "2024-12-05 01:22:26", 6 | "openTimestamp": 1733359946, 7 | "closeTimestamp": 1733361746, 8 | "uid": 87742848, 9 | "amount": 1, 10 | "profit": 0.87, 11 | "percentProfit": 87, 12 | "percentLoss": 100, 13 | "openPrice": 37.81371, 14 | "closePrice": 0, 15 | "command": 1, 16 | "asset": "EURTRY_otc", 17 | "isDemo": 1, 18 | "copyTicket": "", 19 | "openMs": 61, 20 | "optionType": 100, 21 | "isRollover": false, 22 | "isCopySignal": false, 23 | "currency": "USD", 24 | "amountUSD": 1 25 | }, 26 | { 27 | "id": "820c0f87-0d5e-4ca3-8863-34d5bcb96057", 28 | "openTime": "2024-12-05 00:52:25", 29 | "closeTime": "2024-12-05 01:22:25", 30 | "openTimestamp": 1733359945, 31 | "closeTimestamp": 1733361745, 32 | "uid": 87742848, 33 | "amount": 1, 34 | "profit": 0.87, 35 | "percentProfit": 87, 36 | "percentLoss": 100, 37 | "openPrice": 37.81373, 38 | "closePrice": 0, 39 | "command": 0, 40 | "asset": "EURTRY_otc", 41 | "isDemo": 1, 42 | "copyTicket": "", 43 | "openMs": 554, 44 | "optionType": 100, 45 | "isRollover": false, 46 | "isCopySignal": false, 47 | "currency": "USD", 48 | "amountUSD": 1 49 | }, 50 | { 51 | "id": "f1a89ff8-ba51-4637-bc57-b6e125670bae", 52 | "openTime": "2024-12-05 00:52:24", 53 | "closeTime": "2024-12-05 01:22:24", 54 | "openTimestamp": 1733359944, 55 | "closeTimestamp": 1733361744, 56 | "uid": 87742848, 57 | "amount": 1, 58 | "profit": 0.87, 59 | "percentProfit": 87, 60 | "percentLoss": 100, 61 | "openPrice": 37.81374, 62 | "closePrice": 0, 63 | "command": 0, 64 | "asset": "EURTRY_otc", 65 | "isDemo": 1, 66 | "copyTicket": "", 67 | "openMs": 37, 68 | "optionType": 100, 69 | "isRollover": false, 70 | "isCopySignal": false, 71 | "currency": "USD", 72 | "amountUSD": 1 73 | }, 74 | { 75 | "id": "2bc60c5b-e2d7-429e-b090-e4880565c682", 76 | "openTime": "2024-12-05 00:52:24", 77 | "closeTime": "2024-12-05 01:22:24", 78 | "openTimestamp": 1733359944, 79 | "closeTimestamp": 1733361744, 80 | "uid": 87742848, 81 | "amount": 1, 82 | "profit": 0.87, 83 | "percentProfit": 87, 84 | "percentLoss": 100, 85 | "openPrice": 37.81373, 86 | "closePrice": 0, 87 | "command": 1, 88 | "asset": "EURTRY_otc", 89 | "isDemo": 1, 90 | "copyTicket": "", 91 | "openMs": 544, 92 | "optionType": 100, 93 | "isRollover": false, 94 | "isCopySignal": false, 95 | "currency": "USD", 96 | "amountUSD": 1 97 | } 98 | ] 99 | -------------------------------------------------------------------------------- /crates/core/.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | Cargo.lock -------------------------------------------------------------------------------- /crates/core/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "binary-options-tools-core" 3 | version = "0.1.7" 4 | edition = "2024" 5 | repository = "https://github.com/ChipaDevTeam/BinaryOptionsTools-v2" 6 | readme = "README.md" 7 | description = "The core of the `binary-options-tools` crate and the python library `BinaryOptionsToolsV2`." 8 | license = "MIT" 9 | 10 | [features] 11 | 12 | [dependencies] 13 | binary-options-tools-macros = { path = "../macros", version = "0.1.3" } 14 | 15 | anyhow = "1.0.98" 16 | async-channel = "2.3.1" 17 | async-trait = "0.1.88" 18 | chrono = { version = "0.4.41", features = ["serde"] } 19 | futures-util = "0.3.31" 20 | php_serde = "0.6.0" 21 | pin-project-lite = "0.2.16" 22 | rand = "0.9.1" 23 | reqwest = { version = "0.12.15", features = ["json"] } 24 | serde = { version = "1.0.219", features = ["derive"] } 25 | serde_json = { version = "1.0.140", features = [] } 26 | thiserror = "2.0.12" 27 | tokio = { version = "1.44.2", features = ["macros", "io-util", "rt", "sync"] } 28 | tokio-tungstenite = { version = "0.26.2", features = ["native-tls"] } 29 | tracing = "0.1.41" 30 | tracing-subscriber = { version = "0.3.19", features = ["json"] } 31 | url = { version = "2.5.4", features = ["serde"] } 32 | uuid = { version = "1.16.0", features = ["serde"] } 33 | tracing-appender = "0.2.3" 34 | -------------------------------------------------------------------------------- /crates/core/errors.log: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ChipaDevTeam/BinaryOptionsTools-v2/739f401208a7160a076bb2349591bc0a081f1fb1/crates/core/errors.log -------------------------------------------------------------------------------- /crates/core/readme.md: -------------------------------------------------------------------------------- 1 | # This is the core for all the `BinaryOptionsTools-v2` versions in the different languages 2 | 3 | ## Supported Languages (todo) 4 | * Python [Done] 5 | * Rust [Done] 6 | * JavaScript 7 | * C / C++ 8 | * Java 9 | * Dart 10 | 11 | ## Todo 12 | * Clean the code and add more logging info 13 | * Add functions to clean closed trades history 14 | * Add support for testing for multiple different connections, like passing an iterable 15 | * Add error handling in case there is an error parsing some data, to return an error and not keep waiting (It is for the `send_message` function) --> Done 16 | * Add support for pending requests by `time` and by `price` 17 | * Replace the `tokio::sync::oneshot` channels to `async_channel::channel` and id so it works properly 18 | * Create an example folder with examples for `async` and `sync` versions of the library and for each language supported 19 | 20 | ### General 21 | * Make `WebSocketClient` struct more general and create some traits like: 22 | * `Connect` --> How to connect to websocket 23 | * `Processor` --> How to process every `tokio_tungstenite::tungstenite::Message` 24 | * `Sender` --> Struct Or class that will work be shared between threads 25 | * `Data` --> All the possible data management 26 | 27 | ### Pocket Option 28 | * Add support for Signals (No clue how to start) 29 | * Add support for pending trades (Seems easy and will add a lot new features to the api) 30 | 31 | ### Important 32 | * **Pocket Option** server works on the timezone: `UTC +2` -------------------------------------------------------------------------------- /crates/core/src/constants.rs: -------------------------------------------------------------------------------- 1 | pub const MAX_LOGGING_CHANNEL_CAPACITY: usize = 128; 2 | pub const MAX_CHANNEL_CAPACITY: usize = 8; 3 | pub const RECONNECT_CALLBACK: u64 = 5; 4 | /// How much time to wait after the reconnection before starting the callback 5 | pub const TIMEOUT_TIME: u64 = 16; 6 | pub const MAX_ALLOWED_LOOPS: u32 = 8; 7 | pub const SLEEP_INTERVAL: u64 = 2; 8 | -------------------------------------------------------------------------------- /crates/core/src/error.rs: -------------------------------------------------------------------------------- 1 | use std::time::Duration; 2 | 3 | use thiserror::Error; 4 | 5 | use tokio_tungstenite::tungstenite::{Error as TungsteniteError, Message, http}; 6 | 7 | use crate::general::traits::MessageTransfer; 8 | 9 | #[derive(Error, Debug)] 10 | pub enum BinaryOptionsToolsError { 11 | #[error("Failed to parse recieved data: {0}")] 12 | SerdeGeneralParsingError(#[from] serde_json::Error), 13 | #[error("Url parsing failed: {0}")] 14 | UrlParsingError(#[from] url::ParseError), 15 | #[error("{platform} Error, {error}")] 16 | BinaryOptionsTradingError { platform: String, error: String }, 17 | #[error("Error sending request, {0}")] 18 | WebsocketMessageSendingError(String), 19 | #[error("Failed to recieve data from websocket server: {0}")] 20 | WebsocketRecievingConnectionError(String), 21 | #[error("Websocket connection was closed by the server, {0}")] 22 | WebsocketConnectionClosed(String), 23 | #[error("Failed to connect to websocket server: {0}")] 24 | WebsocketConnectionError(#[from] TungsteniteError), 25 | #[error("Failed to send message to websocket sender, {0}")] 26 | MessageSendingError(#[from] async_channel::SendError), 27 | #[error("Failed to send message using asyncronous channel, {0}")] 28 | GeneralMessageSendingError(String), 29 | #[error( 30 | "Failed to reconnect '{0}' times, maximum allowed number of reconnections was reached, breaking" 31 | )] 32 | MaxReconnectAttemptsReached(u32), 33 | #[error( 34 | "Failed to reconnect '{number}' times, maximum allowed number of reconnections is `{max}`" 35 | )] 36 | ReconnectionAttemptFailure { number: u32, max: u32 }, 37 | #[error("Failed to recieve message from separate thread, {0}")] 38 | OneShotRecieverError(#[from] tokio::sync::oneshot::error::RecvError), 39 | #[error("Failed to recieve message from request channel, {0}")] 40 | ChannelRequestRecievingError(#[from] async_channel::RecvError), 41 | #[error("Failed to send message to request channel, {0}")] 42 | ChannelRequestSendingError(String), 43 | #[error("Error recieving response from server, {0}")] 44 | WebSocketMessageError(String), 45 | #[error("Failed to parse data: {0}")] 46 | GeneralParsingError(String), 47 | #[error("Error making http request: {0}")] 48 | HTTPError(#[from] http::Error), 49 | #[error("Unallowed operation, {0}")] 50 | Unallowed(String), 51 | #[error("Failed to join thread, {0}")] 52 | TaskJoinError(#[from] tokio::task::JoinError), 53 | #[error("Failed to execute '{task}' task before the maximum allowed time of '{duration:?}'")] 54 | TimeoutError { task: String, duration: Duration }, 55 | #[error("Failed to parse duration, error {0}")] 56 | ChronoDurationParsingError(#[from] chrono::OutOfRangeError), 57 | #[error("Unknown error during execution, error {0}")] 58 | UnknownError(#[from] anyhow::Error), 59 | } 60 | 61 | pub type BinaryOptionsResult = Result; 62 | 63 | impl From for BinaryOptionsToolsError 64 | where 65 | Transfer: MessageTransfer, 66 | { 67 | fn from(value: Transfer) -> Self { 68 | let error = value.to_error(); 69 | Self::WebsocketMessageSendingError(error.to_string()) 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /crates/core/src/general/config.rs: -------------------------------------------------------------------------------- 1 | use std::{collections::HashSet, time::Duration}; 2 | 3 | use serde::{Deserialize, Serialize}; 4 | use url::Url; 5 | 6 | use crate::constants::{MAX_ALLOWED_LOOPS, RECONNECT_CALLBACK, SLEEP_INTERVAL, TIMEOUT_TIME}; 7 | 8 | use super::{ 9 | traits::{DataHandler, InnerConfig, MessageTransfer}, 10 | types::Callback, 11 | }; 12 | use binary_options_tools_macros::Config; 13 | 14 | #[derive(Serialize, Deserialize, Config)] 15 | pub struct _Config { 16 | pub max_allowed_loops: u32, 17 | pub sleep_interval: u64, 18 | #[config(extra(iterator(dtype = "Url", add_fn = "insert")))] 19 | pub default_connection_url: HashSet, 20 | pub reconnect_time: u64, 21 | #[serde(skip)] 22 | #[config(extra(iterator(dtype = "Callback")))] 23 | pub callbacks: Vec>, 24 | pub connection_initialization_timeout: Duration, 25 | pub timeout: Duration, // General timeout 26 | #[serde(bound = "U: Serialize + for<'d> Deserialize<'d>")] 27 | pub extra: U, 28 | // #[serde(skip)] 29 | // pub callbacks: Arc>> 30 | } 31 | 32 | impl _Config { 33 | pub fn new(initialization_timeout: Duration, callbacks: Vec>, extra: U) -> Self { 34 | Self { 35 | max_allowed_loops: MAX_ALLOWED_LOOPS, 36 | sleep_interval: SLEEP_INTERVAL, 37 | default_connection_url: HashSet::new(), 38 | reconnect_time: RECONNECT_CALLBACK, 39 | callbacks, 40 | timeout: Duration::from_secs(TIMEOUT_TIME), 41 | connection_initialization_timeout: initialization_timeout, 42 | extra, 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /crates/core/src/general/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod client; 2 | pub mod config; 3 | pub mod traits; 4 | pub mod types; 5 | 6 | pub mod send; 7 | pub mod stream; 8 | pub mod validate; 9 | -------------------------------------------------------------------------------- /crates/core/src/general/stream.rs: -------------------------------------------------------------------------------- 1 | use std::{sync::Arc, time::Duration}; 2 | 3 | use async_channel::{Receiver, RecvError}; 4 | use futures_util::{Stream, stream::unfold}; 5 | 6 | use crate::{error::{BinaryOptionsResult, BinaryOptionsToolsError}, utils::time::timeout}; 7 | 8 | use super::traits::ValidatorTrait; 9 | 10 | pub struct RecieverStream { 11 | inner: Receiver, 12 | timeout: Option, 13 | } 14 | 15 | pub struct FilteredRecieverStream { 16 | inner: Receiver, 17 | timeout: Option, 18 | filter: Box + Send + Sync> 19 | } 20 | 21 | 22 | impl RecieverStream { 23 | pub fn new(inner: Receiver) -> Self { 24 | Self { 25 | inner, 26 | timeout: None, 27 | } 28 | } 29 | 30 | pub fn new_timed(inner: Receiver, timeout: Option) -> Self { 31 | Self { inner, timeout } 32 | } 33 | 34 | 35 | async fn receive(&self) -> BinaryOptionsResult { 36 | match self.timeout { 37 | Some(time) => timeout(time, self.inner.recv(), "RecieverStream".to_string()).await, 38 | None => Ok(self.inner.recv().await?), 39 | } 40 | } 41 | 42 | pub fn to_stream(&self) -> impl Stream> + '_ { 43 | Box::pin(unfold(self, move |state| async move { 44 | let item = state.receive().await; 45 | Some((item, state)) 46 | })) 47 | } 48 | 49 | pub fn to_stream_static(self: Arc) -> impl Stream> + 'static 50 | where 51 | T: 'static, 52 | { 53 | Box::pin(unfold(self, async |state| { 54 | let item = state.receive().await; 55 | Some((item, state)) 56 | })) 57 | } 58 | } 59 | 60 | 61 | impl FilteredRecieverStream { 62 | pub fn new(inner: Receiver, timeout: Option, filter: Box + Send + Sync>) -> Self { 63 | Self { inner, timeout, filter } 64 | } 65 | 66 | pub fn new_base(inner: Receiver) -> Self { 67 | Self::new(inner, None, default_filter()) 68 | } 69 | 70 | pub fn new_filtered(inner: Receiver, filter: Box + Send + Sync>) -> Self { 71 | Self::new(inner, None, filter) 72 | } 73 | 74 | 75 | async fn recv(&self) -> BinaryOptionsResult { 76 | while let Ok(msg) = self.inner.recv().await { 77 | if self.filter.validate(&msg) { 78 | return Ok(msg); 79 | } 80 | } 81 | Err(BinaryOptionsToolsError::ChannelRequestRecievingError( 82 | RecvError, 83 | )) 84 | } 85 | 86 | async fn receive(&self) -> BinaryOptionsResult { 87 | match self.timeout { 88 | Some(time) => timeout(time, self.recv(), "RecieverStream".to_string()).await, 89 | None => Ok(self.inner.recv().await?), 90 | } 91 | } 92 | 93 | pub fn to_stream(&self) -> impl Stream> + '_ { 94 | Box::pin(unfold(self, move |state| async move { 95 | let item = state.receive().await; 96 | Some((item, state)) 97 | })) 98 | } 99 | 100 | pub fn to_stream_static(self: Arc) -> impl Stream> + 'static 101 | where 102 | T: 'static, 103 | { 104 | Box::pin(unfold(self, async |state| { 105 | let item = state.receive().await; 106 | Some((item, state)) 107 | })) 108 | } 109 | } 110 | 111 | fn default_filter() -> Box + Send + Sync> { 112 | Box::new(move |_: &T| { 113 | true 114 | }) 115 | } -------------------------------------------------------------------------------- /crates/core/src/general/traits.rs: -------------------------------------------------------------------------------- 1 | use async_trait::async_trait; 2 | use core::{error, fmt, hash}; 3 | use serde::{Serialize, de::DeserializeOwned}; 4 | use tokio::net::TcpStream; 5 | use tokio_tungstenite::{MaybeTlsStream, WebSocketStream, tungstenite::Message}; 6 | 7 | use crate::error::BinaryOptionsResult; 8 | 9 | use super::{ 10 | config::Config, 11 | send::SenderMessage, 12 | types::{Data, MessageType}, 13 | }; 14 | 15 | /// This trait makes sure that the struct passed to the `WebsocketClient` can be cloned, sended through multiple threads, and serialized and deserialized using serde 16 | pub trait Credentials: Clone + Send + Sync + Serialize + DeserializeOwned {} 17 | 18 | /// This trait is used to allow users to pass their own config struct to the `WebsocketClient` 19 | pub trait InnerConfig: DeserializeOwned + Clone + Send {} 20 | 21 | /// This trait allows users to pass their own way of storing and updating recieved data from the `websocket` connection 22 | #[async_trait] 23 | pub trait DataHandler: Clone + Send + Sync { 24 | type Transfer: MessageTransfer; 25 | 26 | async fn update(&self, message: &Self::Transfer) -> BinaryOptionsResult<()>; 27 | } 28 | 29 | /// Allows users to add a callback that will be called when the websocket connection is established after being disconnected, you will have access to the `Data` struct providing access to any required information stored during execution 30 | #[async_trait] 31 | pub trait WCallback: Send + Sync { 32 | type T: DataHandler; 33 | type Transfer: MessageTransfer; 34 | type U: InnerConfig; 35 | 36 | async fn call( 37 | &self, 38 | data: Data, 39 | sender: &SenderMessage, 40 | config: &Config 41 | ) -> BinaryOptionsResult<()>; 42 | } 43 | 44 | /// Main entry point for the `WebsocketClient` struct, this trait is used by the client to handle incoming messages, return data to user and a lot more things 45 | pub trait MessageTransfer: 46 | DeserializeOwned + Clone + Into + Send + Sync + error::Error + fmt::Debug + fmt::Display 47 | { 48 | type Error: Into + Clone + error::Error; 49 | type TransferError: error::Error; 50 | type Info: MessageInformation; 51 | type Raw: RawMessage; 52 | 53 | fn info(&self) -> Self::Info; 54 | 55 | fn error(&self) -> Option; 56 | 57 | fn to_error(&self) -> Self::TransferError; 58 | 59 | fn error_info(&self) -> Option>; 60 | } 61 | 62 | pub trait MessageInformation: 63 | Serialize + DeserializeOwned + Clone + Send + Sync + Eq + hash::Hash + fmt::Debug + fmt::Display 64 | { 65 | } 66 | 67 | pub trait RawMessage: 68 | Serialize + DeserializeOwned + Clone + Send + Sync + fmt::Debug + fmt::Display 69 | { 70 | fn message(&self) -> Message { 71 | Message::text(self.to_string()) 72 | } 73 | } 74 | 75 | #[async_trait] 76 | /// Every struct that implements MessageHandler will recieve a message and should return 77 | pub trait MessageHandler: Clone + Send + Sync { 78 | type Transfer: MessageTransfer; 79 | 80 | async fn process_message( 81 | &self, 82 | message: &Message, 83 | previous: &Option<<::Transfer as MessageTransfer>::Info>, 84 | sender: &SenderMessage, 85 | ) -> BinaryOptionsResult<(Option>, bool)>; 86 | } 87 | 88 | #[async_trait] 89 | pub trait Connect: Clone + Send + Sync { 90 | type Creds: Credentials; 91 | // type Uris: Iterator; 92 | 93 | async fn connect( 94 | &self, 95 | creds: Self::Creds, 96 | config: &Config, 97 | ) -> BinaryOptionsResult>>; 98 | } 99 | 100 | pub trait ValidatorTrait { 101 | fn validate(&self, message: &T) -> bool; 102 | } 103 | 104 | impl ValidatorTrait for F 105 | where 106 | F: Fn(&T) -> bool + Send + Sync, 107 | { 108 | fn validate(&self, message: &T) -> bool { 109 | self(message) 110 | } 111 | } 112 | 113 | impl InnerConfig for T where T: DeserializeOwned + Clone + Send {} -------------------------------------------------------------------------------- /crates/core/src/general/validate.rs: -------------------------------------------------------------------------------- 1 | use crate::error::{BinaryOptionsResult, BinaryOptionsToolsError}; 2 | 3 | use super::traits::{MessageTransfer, ValidatorTrait}; 4 | 5 | pub fn validate( 6 | validator: &Box + Send + Sync>, 7 | message: Transfer, 8 | ) -> BinaryOptionsResult> 9 | where 10 | Transfer: MessageTransfer, 11 | { 12 | if let Some(e) = message.error() { 13 | Err(BinaryOptionsToolsError::WebSocketMessageError( 14 | e.to_string(), 15 | )) 16 | } else if validator.validate(&message) { 17 | Ok(Some(message)) 18 | } else { 19 | Ok(None) 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /crates/core/src/lib.rs: -------------------------------------------------------------------------------- 1 | pub mod constants; 2 | pub mod error; 3 | pub mod general; 4 | pub mod reimports; 5 | pub mod utils; 6 | 7 | pub mod macros { 8 | pub use binary_options_tools_macros::RegionImpl; 9 | } 10 | -------------------------------------------------------------------------------- /crates/core/src/reimports.rs: -------------------------------------------------------------------------------- 1 | pub use tokio_tungstenite::{ 2 | Connector, MaybeTlsStream, WebSocketStream, connect_async_tls_with_config, 3 | tungstenite::{Bytes, Message, handshake::client::generate_key, http::Request}, 4 | }; 5 | -------------------------------------------------------------------------------- /crates/core/src/utils/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod time; 2 | pub mod tracing; 3 | -------------------------------------------------------------------------------- /crates/core/src/utils/time.rs: -------------------------------------------------------------------------------- 1 | use std::time::Duration; 2 | 3 | use crate::error::{BinaryOptionsResult, BinaryOptionsToolsError}; 4 | use core::future::Future; 5 | 6 | pub async fn timeout(duration: Duration, future: F, task: String) -> BinaryOptionsResult 7 | where 8 | E: Into, 9 | F: Future>, 10 | { 11 | let res = tokio::select! { 12 | _ = tokio::time::sleep(duration) => Err(BinaryOptionsToolsError::TimeoutError { task, duration }), 13 | result = future => match result { 14 | Ok(value) => Ok(value), 15 | Err(err) => Err(err.into()), 16 | }, 17 | }; 18 | res 19 | } 20 | -------------------------------------------------------------------------------- /crates/core/src/utils/tracing.rs: -------------------------------------------------------------------------------- 1 | use std::{fs::OpenOptions, io::Write, time::Duration}; 2 | 3 | use async_channel::{Sender, bounded}; 4 | use serde_json::Value; 5 | use tracing::level_filters::LevelFilter; 6 | use tracing_subscriber::{ 7 | Layer, Registry, 8 | fmt::{self, MakeWriter}, 9 | layer::SubscriberExt, 10 | util::SubscriberInitExt, 11 | }; 12 | 13 | use crate::{constants::MAX_LOGGING_CHANNEL_CAPACITY, general::stream::RecieverStream}; 14 | 15 | pub fn start_tracing(terminal: bool) -> anyhow::Result<()> { 16 | let error_logs = OpenOptions::new() 17 | .append(true) 18 | .create(true) 19 | .open("errors.log")?; 20 | 21 | let sub = tracing_subscriber::registry() 22 | // .with(filtered_layer) 23 | .with( 24 | // log-error file, to log the errors that arise 25 | fmt::layer() 26 | .with_ansi(false) 27 | .with_writer(error_logs) 28 | .with_filter(LevelFilter::WARN), 29 | ); 30 | if terminal { 31 | sub.with(fmt::Layer::default().with_filter(LevelFilter::DEBUG)) 32 | .try_init()?; 33 | } else { 34 | sub.try_init()?; 35 | } 36 | 37 | Ok(()) 38 | } 39 | 40 | pub fn start_tracing_leveled(terminal: bool, level: LevelFilter) -> anyhow::Result<()> { 41 | let error_logs = OpenOptions::new() 42 | .append(true) 43 | .create(true) 44 | .open("errors.log")?; 45 | 46 | let sub = tracing_subscriber::registry() 47 | // .with(filtered_layer) 48 | .with( 49 | // log-error file, to log the errors that arise 50 | fmt::layer() 51 | .with_ansi(false) 52 | .with_writer(error_logs) 53 | .with_filter(LevelFilter::WARN), 54 | ); 55 | if terminal { 56 | sub.with(fmt::Layer::default().with_filter(level)) 57 | .try_init()?; 58 | } else { 59 | sub.try_init()?; 60 | } 61 | 62 | Ok(()) 63 | } 64 | 65 | #[derive(Clone)] 66 | pub struct StreamWriter { 67 | sender: Sender, 68 | } 69 | 70 | impl Write for StreamWriter { 71 | fn write(&mut self, buf: &[u8]) -> std::io::Result { 72 | if let Ok(item) = serde_json::from_slice::(buf) { 73 | self.sender 74 | .send_blocking(item.to_string()) 75 | .map_err(std::io::Error::other)?; 76 | } 77 | Ok(buf.len()) 78 | } 79 | 80 | fn flush(&mut self) -> std::io::Result<()> { 81 | Ok(()) 82 | } 83 | } 84 | 85 | impl<'a> MakeWriter<'a> for StreamWriter { 86 | type Writer = StreamWriter; 87 | fn make_writer(&'a self) -> Self::Writer { 88 | self.clone() 89 | } 90 | } 91 | 92 | pub fn stream_logs_layer( 93 | level: LevelFilter, 94 | timout: Option, 95 | ) -> ( 96 | Box + Send + Sync>, 97 | RecieverStream, 98 | ) { 99 | let (sender, receiver) = bounded(MAX_LOGGING_CHANNEL_CAPACITY); 100 | let receiver = RecieverStream::new_timed(receiver, timout); 101 | let writer = StreamWriter { sender }; 102 | let layer = tracing_subscriber::fmt::layer::() 103 | .json() 104 | .flatten_event(true) 105 | .with_writer(writer) 106 | .with_filter(level) 107 | .boxed(); 108 | (layer, receiver) 109 | } 110 | -------------------------------------------------------------------------------- /crates/macros/.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | Cargo.lock -------------------------------------------------------------------------------- /crates/macros/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "binary-options-tools-macros" 3 | version = "0.1.4" 4 | edition = "2021" 5 | repository = "https://github.com/ChipaDevTeam/BinaryOptionsTools-v2" 6 | readme = "README.md" 7 | description = "Macros for the `binary-options-tools` crate" 8 | license = "MIT" 9 | 10 | [lib] 11 | proc-macro = true 12 | 13 | [dependencies] 14 | # binary-options-tools-core = { path = "../core", version = "0.1.5" } 15 | 16 | anyhow = "1.0.98" 17 | proc-macro2 = "1.0.95" 18 | quote = "1.0.40" 19 | serde_json = "1.0.140" 20 | syn = "2.0.101" 21 | tokio = { version = "1.44.2", default-features = false, features = ["macros"] } 22 | tracing = "0.1.41" 23 | darling = "0.20.11" 24 | url = { version = "2.5.4", features = ["serde"] } 25 | serde = { version = "1.0.219", features = ["derive"] } 26 | 27 | # raw_core = { path = "../raw_core" } 28 | 29 | [dev-dependencies] 30 | serde = "1.0.219" 31 | -------------------------------------------------------------------------------- /crates/macros/readme.md: -------------------------------------------------------------------------------- 1 | # Some simple macros for the `binary-options-tools` crate -------------------------------------------------------------------------------- /crates/macros/src/deserialize.rs: -------------------------------------------------------------------------------- 1 | use quote::{quote, ToTokens}; 2 | use syn::{parse::Parse, Expr, Token, Type}; 3 | 4 | pub struct Deserializer { 5 | res_type: Type, 6 | data: Expr, 7 | } 8 | 9 | impl Parse for Deserializer { 10 | fn parse(input: syn::parse::ParseStream) -> syn::Result { 11 | let res_type = input.parse()?; 12 | let _: Token![,] = input.parse()?; 13 | let data = input.parse()?; 14 | Ok(Self { res_type, data }) 15 | } 16 | } 17 | 18 | impl ToTokens for Deserializer { 19 | fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) { 20 | let res_type = &self.res_type; 21 | let data = &self.data; 22 | tokens.extend(quote! { 23 | ::serde_json::from_str::<#res_type>(&std::string::ToString::to_string(#data)) 24 | }); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /crates/macros/src/impls/mod.rs: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /crates/macros/src/lib.rs: -------------------------------------------------------------------------------- 1 | mod config; 2 | mod deserialize; 3 | mod impls; 4 | mod region; 5 | mod serialize; 6 | mod timeout; 7 | 8 | use config::Config; 9 | use deserialize::Deserializer; 10 | use region::RegionImpl; 11 | use timeout::{Timeout, TimeoutArgs, TimeoutBody}; 12 | 13 | use darling::FromDeriveInput; 14 | use proc_macro::TokenStream; 15 | use quote::quote; 16 | use serialize::Serializer; 17 | use syn::{parse_macro_input, DeriveInput}; 18 | 19 | #[proc_macro] 20 | pub fn deserialize(input: TokenStream) -> TokenStream { 21 | let d = parse_macro_input!(input as Deserializer); 22 | quote! { #d }.into() 23 | } 24 | 25 | #[proc_macro] 26 | pub fn serialize(input: TokenStream) -> TokenStream { 27 | let s = parse_macro_input!(input as Serializer); 28 | quote! { #s }.into() 29 | } 30 | 31 | /// This macro wraps any async function and transforms it's output `T` into `anyhow::Result`, 32 | /// if the function doesn't end before the timout it will rais an error 33 | /// The macro also supports creating a `#[tracing::instrument]` macro with all the params inside `tracing(args)` 34 | /// Example: 35 | /// #[timeout(10, tracing(skip(non_debug_input)))] 36 | /// #[timeout(12)] 37 | #[proc_macro_attribute] 38 | pub fn timeout(attr: TokenStream, item: TokenStream) -> TokenStream { 39 | let args = parse_macro_input!(attr as TimeoutArgs); 40 | let body = parse_macro_input!(item as TimeoutBody); 41 | let timeout = Timeout::new(body, args); 42 | let q = quote! { #timeout }; 43 | 44 | // println!("{q}"); 45 | q.into() 46 | } 47 | 48 | #[proc_macro_derive(Config, attributes(config))] 49 | pub fn config(input: TokenStream) -> TokenStream { 50 | let parsed = parse_macro_input!(input as DeriveInput); 51 | let config = Config::from_derive_input(&parsed).unwrap(); 52 | quote! { #config }.into() 53 | } 54 | 55 | #[proc_macro_derive(RegionImpl, attributes(region))] 56 | pub fn region(input: TokenStream) -> TokenStream { 57 | let parsed = parse_macro_input!(input as DeriveInput); 58 | let region = RegionImpl::from_derive_input(&parsed).unwrap(); 59 | quote! { #region }.into() 60 | } 61 | -------------------------------------------------------------------------------- /crates/macros/src/region.rs: -------------------------------------------------------------------------------- 1 | use darling::{util::Override, FromDeriveInput}; 2 | use proc_macro2::{Span, TokenStream}; 3 | use quote::{quote, ToTokens}; 4 | use serde::Deserialize; 5 | use std::collections::HashSet; 6 | use std::fs::File; 7 | use std::hash::Hash; 8 | use std::io::Read; 9 | use std::path::PathBuf; 10 | use syn::Ident; 11 | use url::Url; 12 | 13 | #[derive(Debug, FromDeriveInput)] 14 | #[darling(attributes(region))] 15 | pub struct RegionImpl { 16 | ident: Ident, 17 | path: Override, 18 | } 19 | 20 | #[derive(Debug, Deserialize)] 21 | struct Regions(HashSet); 22 | 23 | #[derive(Debug, Deserialize)] 24 | struct Region { 25 | name: String, 26 | url: Url, 27 | latitude: f64, 28 | longitude: f64, 29 | demo: bool, 30 | } 31 | 32 | impl RegionImpl { 33 | fn regions(&self) -> anyhow::Result { 34 | let mut file = File::open( 35 | self.path 36 | .as_ref() 37 | .explicit() 38 | .ok_or(anyhow::anyhow!("Error"))?, 39 | )?; 40 | let mut buff = String::new(); 41 | file.read_to_string(&mut buff)?; 42 | 43 | Ok(serde_json::from_str(&buff)?) 44 | } 45 | } 46 | 47 | impl ToTokens for RegionImpl { 48 | fn to_tokens(&self, tokens: &mut TokenStream) { 49 | let name = &self.ident; 50 | let implementation = &self.regions().unwrap(); 51 | 52 | tokens.extend(quote! { 53 | impl #name { 54 | #implementation 55 | } 56 | }); 57 | } 58 | } 59 | 60 | impl ToTokens for Regions { 61 | fn to_tokens(&self, tokens: &mut TokenStream) { 62 | let regions: &Vec<&Region> = &self.0.iter().collect(); 63 | let demos: Vec<&Region> = regions.iter().filter_map(|r| r.get_demo()).collect(); 64 | let demos_stream = demos.iter().map(|r| r.to_stream()); 65 | let demos_url = demos.iter().map(|r| r.url()); 66 | let reals: Vec<&Region> = regions.iter().filter_map(|r| r.get_real()).collect(); 67 | let reals_stream = reals.iter().map(|r| r.to_stream()); 68 | let reals_url = reals.iter().map(|r| r.url()); 69 | 70 | tokens.extend(quote! { 71 | #(#regions)* 72 | 73 | pub fn demo_regions() -> Vec<(&'static str, f64, f64)> { 74 | vec![#(#demos_stream),*] 75 | } 76 | 77 | pub fn regions() -> Vec<(&'static str, f64, f64)> { 78 | vec![#(#reals_stream),*] 79 | } 80 | 81 | pub fn demo_regions_str() -> Vec<&'static str> { 82 | ::std::vec::Vec::from([#(#demos_url),*]) 83 | } 84 | 85 | pub fn regions_str() -> Vec<&'static str> { 86 | ::std::vec::Vec::from([#(#reals_url),*]) 87 | } 88 | }); 89 | } 90 | } 91 | 92 | impl ToTokens for Region { 93 | fn to_tokens(&self, tokens: &mut TokenStream) { 94 | let name = self.name(); 95 | let url = &self.url.to_string(); 96 | let latitude = self.latitude; 97 | let longitude = self.longitude; 98 | tokens.extend(quote! { 99 | pub const #name: (&str, f64, f64) = (#url, #latitude, #longitude); 100 | }); 101 | } 102 | } 103 | 104 | impl PartialEq for Region { 105 | fn eq(&self, other: &Self) -> bool { 106 | self.name == other.name 107 | } 108 | } 109 | 110 | impl Eq for Region {} 111 | 112 | impl Hash for Region { 113 | fn hash(&self, state: &mut H) { 114 | self.name.hash(state); 115 | } 116 | } 117 | 118 | impl Region { 119 | fn name(&self) -> Ident { 120 | Ident::new(&self.name.to_uppercase(), Span::call_site()) 121 | } 122 | 123 | fn url(&self) -> TokenStream { 124 | let name = self.name(); 125 | quote! { 126 | Self::#name.0 127 | } 128 | } 129 | 130 | fn to_stream(&self) -> TokenStream { 131 | let name = self.name(); 132 | quote! { 133 | Self::#name 134 | } 135 | } 136 | 137 | fn get_demo(&self) -> Option<&Self> { 138 | if self.demo { 139 | Some(self) 140 | } else { 141 | None 142 | } 143 | } 144 | 145 | fn get_real(&self) -> Option<&Self> { 146 | if !self.demo { 147 | Some(self) 148 | } else { 149 | None 150 | } 151 | } 152 | } 153 | -------------------------------------------------------------------------------- /crates/macros/src/serialize.rs: -------------------------------------------------------------------------------- 1 | use quote::{quote, ToTokens}; 2 | use syn::{parse::Parse, Expr}; 3 | 4 | pub struct Serializer { 5 | value: Expr, 6 | } 7 | 8 | impl Parse for Serializer { 9 | fn parse(input: syn::parse::ParseStream) -> syn::Result { 10 | input.parse().map(|value| Self { value }) 11 | } 12 | } 13 | 14 | impl ToTokens for Serializer { 15 | fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) { 16 | let value = &self.value; 17 | tokens.extend(quote! { 18 | ::serde_json::to_string(#value) 19 | }); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /data/OTC-assets.txt: -------------------------------------------------------------------------------- 1 | #AAPL_otc 2 | #AXP_otc 3 | #BA_otc 4 | #CSCO_otc 5 | #FB_otc 6 | #INTC_otc 7 | #JNJ_otc 8 | #MCD_otc 9 | #MSFT_otc 10 | #PFE_otc 11 | #TSLA_otc 12 | #XOM_otc 13 | 100GBP_otc 14 | ADA-USD_otc 15 | AEDCNY_otc 16 | AMZN_otc 17 | AUDCAD_otc 18 | AUDCHF_otc 19 | AUDJPY_otc 20 | AUDNZD_otc 21 | AUDUSD_otc 22 | AUS200_otc 23 | AVAX_otc 24 | BABA_otc 25 | BHDCNY_otc 26 | BITB_otc 27 | BNB-USD_otc 28 | BTCUSD_otc 29 | CADCHF_otc 30 | CADJPY_otc 31 | CHFJPY_otc 32 | CHFNOK_otc 33 | CITI_otc 34 | D30EUR_otc 35 | DJI30_otc 36 | DOGE_otc 37 | DOTUSD_otc 38 | E35EUR_otc 39 | E50EUR_otc 40 | ETHUSD_otc 41 | EURCHF_otc 42 | EURGBP_otc 43 | EURHUF_otc 44 | EURJPY_otc 45 | EURNZD_otc 46 | EURRUB_otc 47 | EURTRY_otc 48 | EURUSD_otc 49 | F40EUR_otc 50 | FDX_otc 51 | GBPAUD_otc 52 | GBPJPY_otc 53 | GBPUSD_otc 54 | IRRUSD_otc 55 | JODCNY_otc 56 | JPN225_otc 57 | LBPUSD_otc 58 | LINK_otc 59 | LTCUSD_otc 60 | MADUSD_otc 61 | MATIC_otc 62 | NASUSD_otc 63 | NFLX_otc 64 | NZDJPY_otc 65 | NZDUSD_otc 66 | OMRCNY_otc 67 | QARCNY_otc 68 | SARCNY_otc 69 | SOL-USD_otc 70 | SP500_otc 71 | SYPUSD_otc 72 | TNDUSD_otc 73 | TON-USD_otc 74 | TRX-USD_otc 75 | TWITTER_otc 76 | UKBrent_otc 77 | USCrude_otc 78 | USDARS_otc 79 | USDBDT_otc 80 | USDBRL_otc 81 | USDCAD_otc 82 | USDCHF_otc 83 | USDCLP_otc 84 | USDCNH_otc 85 | USDCOP_otc 86 | USDDZD_otc 87 | USDEGP_otc 88 | USDIDR_otc 89 | USDINR_otc 90 | USDJPY_otc 91 | USDMXN_otc 92 | USDMYR_otc 93 | USDPHP_otc 94 | USDPKR_otc 95 | USDRUB_otc 96 | USDSGD_otc 97 | USDTHB_otc 98 | USDVND_otc 99 | VISA_otc 100 | XAGUSD_otc 101 | XAUUSD_otc 102 | XNGUSD_otc 103 | XPDUSD_otc 104 | XPTUSD_otc 105 | XRPUSD_otc 106 | YERUSD_otc 107 | -------------------------------------------------------------------------------- /data/assets-otc.tested.txt: -------------------------------------------------------------------------------- 1 | #AAPL_otc 2 | #AXP_otc 3 | #BA_otc 4 | #CSCO_otc 5 | #FB_otc 6 | #INTC_otc 7 | #JNJ_otc 8 | #MCD_otc 9 | #MSFT_otc 10 | #PFE_otc 11 | #TSLA_otc 12 | #XOM_otc 13 | 100GBP_otc 14 | ADA-USD_otc 15 | AEDCNY_otc 16 | AMZN_otc 17 | AUDCAD_otc 18 | AUDCHF_otc 19 | AUDJPY_otc 20 | AUDNZD_otc 21 | AUDUSD_otc 22 | AUS200_otc 23 | AVAX_otc 24 | BABA_otc 25 | BHDCNY_otc 26 | BITB_otc 27 | BNB-USD_otc 28 | BTCUSD_otc 29 | CADCHF_otc 30 | CADJPY_otc 31 | CHFJPY_otc 32 | CHFNOK_otc 33 | CITI_otc 34 | D30EUR_otc 35 | DJI30_otc 36 | DOGE_otc 37 | DOTUSD_otc 38 | E35EUR_otc 39 | E50EUR_otc 40 | ETHUSD_otc 41 | EURCHF_otc 42 | EURGBP_otc 43 | EURHUF_otc 44 | EURJPY_otc 45 | EURNZD_otc 46 | EURRUB_otc 47 | EURTRY_otc 48 | EURUSD_otc 49 | F40EUR_otc 50 | FDX_otc 51 | GBPAUD_otc 52 | GBPJPY_otc 53 | GBPUSD_otc 54 | IRRUSD_otc 55 | JODCNY_otc 56 | JPN225_otc 57 | LBPUSD_otc 58 | LINK_otc 59 | LTCUSD_otc 60 | MADUSD_otc 61 | MATIC_otc 62 | NASUSD_otc 63 | NFLX_otc 64 | NZDJPY_otc 65 | NZDUSD_otc 66 | OMRCNY_otc 67 | QARCNY_otc 68 | SARCNY_otc 69 | SOL-USD_otc 70 | SP500_otc 71 | SYPUSD_otc 72 | TNDUSD_otc 73 | TON-USD_otc 74 | TRX-USD_otc 75 | UKBrent_otc 76 | USCrude_otc 77 | USDARS_otc 78 | USDBDT_otc 79 | USDBRL_otc 80 | USDCAD_otc 81 | USDCHF_otc 82 | USDCLP_otc 83 | USDCNH_otc 84 | USDCOP_otc 85 | USDDZD_otc 86 | USDEGP_otc 87 | USDIDR_otc 88 | USDINR_otc 89 | USDJPY_otc 90 | USDMXN_otc 91 | USDMYR_otc 92 | USDPHP_otc 93 | USDPKR_otc 94 | USDRUB_otc 95 | USDSGD_otc 96 | USDTHB_otc 97 | USDVND_otc 98 | VISA_otc 99 | XAGUSD_otc 100 | XAUUSD_otc 101 | XNGUSD_otc 102 | XPDUSD_otc 103 | XPTUSD_otc 104 | YERUSD_otc 105 | -------------------------------------------------------------------------------- /data/assets.txt: -------------------------------------------------------------------------------- 1 | #AAPL 2 | #AAPL_otc 3 | #AXP 4 | #AXP_otc 5 | #BA 6 | #BA_otc 7 | #CSCO 8 | #CSCO_otc 9 | #FB 10 | #FB_otc 11 | #INTC 12 | #INTC_otc 13 | #JNJ 14 | #JNJ_otc 15 | #JPM 16 | #MCD 17 | #MCD_otc 18 | #MSFT 19 | #MSFT_otc 20 | #PFE 21 | #PFE_otc 22 | #TSLA 23 | #TSLA_otc 24 | #XOM 25 | #XOM_otc 26 | 100GBP 27 | 100GBP_otc 28 | ADA-USD_otc 29 | AEDCNY_otc 30 | AEX25 31 | AMZN_otc 32 | AUDCAD 33 | AUDCAD_otc 34 | AUDCHF 35 | AUDCHF_otc 36 | AUDJPY 37 | AUDJPY_otc 38 | AUDNZD_otc 39 | AUDUSD 40 | AUDUSD_otc 41 | AUS200 42 | AUS200_otc 43 | AVAX_otc 44 | BABA 45 | BABA_otc 46 | BCHEUR 47 | BCHGBP 48 | BCHJPY 49 | BHDCNY_otc 50 | BITB_otc 51 | BNB-USD_otc 52 | BTCGBP 53 | BTCJPY 54 | BTCUSD 55 | BTCUSD_otc 56 | CAC40 57 | CADCHF 58 | CADCHF_otc 59 | CADJPY 60 | CADJPY_otc 61 | CHFJPY 62 | CHFJPY_otc 63 | CHFNOK_otc 64 | CITI 65 | CITI_otc 66 | D30EUR 67 | D30EUR_otc 68 | DASH_USD 69 | DJI30 70 | DJI30_otc 71 | DOGE_otc 72 | DOTUSD_otc 73 | E35EUR 74 | E35EUR_otc 75 | E50EUR 76 | E50EUR_otc 77 | ETHUSD 78 | ETHUSD_otc 79 | EURAUD 80 | EURCAD 81 | EURCHF 82 | EURCHF_otc 83 | EURGBP 84 | EURGBP_otc 85 | EURHUF_otc 86 | EURJPY 87 | EURJPY_otc 88 | EURNZD_otc 89 | EURRUB_otc 90 | EURTRY_otc 91 | EURUSD 92 | EURUSD_otc 93 | F40EUR 94 | F40EUR_otc 95 | FDX_otc 96 | GBPAUD 97 | GBPAUD_otc 98 | GBPCAD 99 | GBPCHF 100 | GBPJPY 101 | GBPJPY_otc 102 | GBPUSD 103 | GBPUSD_otc 104 | H33HKD 105 | IRRUSD_otc 106 | JODCNY_otc 107 | JPN225 108 | JPN225_otc 109 | LBPUSD_otc 110 | LINK_otc 111 | LNKUSD 112 | LTCUSD_otc 113 | MADUSD_otc 114 | MATIC_otc 115 | NASUSD 116 | NASUSD_otc 117 | NFLX 118 | NFLX_otc 119 | NZDJPY_otc 120 | NZDUSD_otc 121 | OMRCNY_otc 122 | QARCNY_otc 123 | SARCNY_otc 124 | SMI20 125 | SOL-USD_otc 126 | SP500 127 | SP500_otc 128 | SYPUSD_otc 129 | TNDUSD_otc 130 | TON-USD_otc 131 | TRX-USD_otc 132 | TWITTER 133 | TWITTER_otc 134 | UKBrent 135 | UKBrent_otc 136 | USCrude 137 | USCrude_otc 138 | USDARS_otc 139 | USDBDT_otc 140 | USDBRL_otc 141 | USDCAD 142 | USDCAD_otc 143 | USDCHF 144 | USDCHF_otc 145 | USDCLP_otc 146 | USDCNH_otc 147 | USDCOP_otc 148 | USDDZD_otc 149 | USDEGP_otc 150 | USDIDR_otc 151 | USDINR_otc 152 | USDJPY 153 | USDJPY_otc 154 | USDMXN_otc 155 | USDMYR_otc 156 | USDPHP_otc 157 | USDPKR_otc 158 | USDRUB_otc 159 | USDSGD_otc 160 | USDTHB_otc 161 | USDVND_otc 162 | VISA_otc 163 | XAGEUR 164 | XAGUSD 165 | XAGUSD_otc 166 | XAUEUR 167 | XAUUSD 168 | XAUUSD_otc 169 | XNGUSD 170 | XNGUSD_otc 171 | XPDUSD 172 | XPDUSD_otc 173 | XPTUSD 174 | XPTUSD_otc 175 | XRPUSD_otc 176 | YERUSD_otc 177 | -------------------------------------------------------------------------------- /docker/android/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM rust:1.76-slim 2 | 3 | # Install system dependencies 4 | RUN apt-get update && apt-get install -y \ 5 | curl unzip build-essential pkg-config cmake \ 6 | python3 python3-pip python3-venv \ 7 | clang git libssl-dev \ 8 | && rm -rf /var/lib/apt/lists/* 9 | 10 | # Create a virtualenv and install maturin inside 11 | ENV VENV_PATH=/opt/venv 12 | RUN python3 -m venv $VENV_PATH 13 | ENV PATH="$VENV_PATH/bin:$PATH" 14 | 15 | RUN pip install --upgrade pip && pip install maturin 16 | 17 | # Android NDK setup 18 | ENV ANDROID_NDK_VERSION=r26d 19 | ENV ANDROID_SDK_ROOT=/opt/android-sdk 20 | ENV ANDROID_NDK_HOME=$ANDROID_SDK_ROOT/ndk/$ANDROID_NDK_VERSION 21 | ENV PATH="$ANDROID_NDK_HOME/toolchains/llvm/prebuilt/linux-x86_64/bin:$PATH" 22 | 23 | RUN mkdir -p $ANDROID_SDK_ROOT/ndk && \ 24 | curl -L https://dl.google.com/android/repository/android-ndk-${ANDROID_NDK_VERSION}-linux.zip -o ndk.zip && \ 25 | unzip ndk.zip -d $ANDROID_SDK_ROOT/ndk && \ 26 | rm ndk.zip 27 | 28 | # Add Android Rust targets 29 | RUN rustup target add aarch64-linux-android 30 | 31 | COPY ../../BinaryOptionsToolsV2 . 32 | 33 | ENV CC_aarch64_linux_android=aarch64-linux-android21-clang 34 | ENV CARGO_TARGET_AARCH64_LINUX_ANDROID_LINKER=aarch64-linux-android21-clang 35 | 36 | # Build .whl using maturin 37 | CMD ["maturin", "build", "--release", "--target", "aarch64-linux-android", "--interpreter", "python3"] 38 | -------------------------------------------------------------------------------- /docker/linux/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM rust:1.76-slim 2 | 3 | # Install system dependencies 4 | RUN apt-get update && apt-get install -y \ 5 | curl unzip build-essential pkg-config cmake \ 6 | python3 python3-pip python3-venv \ 7 | clang git libssl-dev \ 8 | && rm -rf /var/lib/apt/lists/* 9 | 10 | # Create a virtualenv and install maturin inside 11 | ENV VENV_PATH=/opt/venv 12 | RUN python3 -m venv $VENV_PATH 13 | ENV PATH="$VENV_PATH/bin:$PATH" 14 | 15 | RUN pip install --upgrade pip && pip install maturin 16 | 17 | COPY ../../BinaryOptionsToolsV2 . 18 | 19 | # Build .whl using maturin 20 | CMD ["maturin", "build", "--release", "--target", "aarch64-linux-android", "--interpreter", "python3"] 21 | -------------------------------------------------------------------------------- /docker/macos/Dockerfile: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ChipaDevTeam/BinaryOptionsTools-v2/739f401208a7160a076bb2349591bc0a081f1fb1/docker/macos/Dockerfile -------------------------------------------------------------------------------- /docker/windows/Dockerfile: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ChipaDevTeam/BinaryOptionsTools-v2/739f401208a7160a076bb2349591bc0a081f1fb1/docker/windows/Dockerfile -------------------------------------------------------------------------------- /docs/.nojekyll: -------------------------------------------------------------------------------- 1 | # This file tells GitHub Pages to skip Jekyll processing 2 | # and serve the site as static files 3 | -------------------------------------------------------------------------------- /docs/_config.yml: -------------------------------------------------------------------------------- 1 | # GitHub Pages Configuration for BinaryOptionsToolsV2 Documentation 2 | title: "BinaryOptionsToolsV2 Documentation" 3 | description: "High-performance binary options trading tools with multi-language support (Python, JavaScript, Rust)" 4 | url: "https://yourusername.github.io" 5 | baseurl: "/BinaryOptionsTools-v2-1" 6 | 7 | # Build settings 8 | markdown: kramdown 9 | highlighter: rouge 10 | plugins: 11 | - jekyll-sitemap 12 | - jekyll-feed 13 | - jekyll-seo-tag 14 | 15 | # Site settings 16 | lang: en 17 | author: "BinaryOptionsToolsV2 Team" 18 | twitter: 19 | username: yourusername 20 | social: 21 | name: BinaryOptionsToolsV2 22 | links: 23 | - https://github.com/yourusername/BinaryOptionsTools-v2-1 24 | 25 | # SEO settings 26 | google_site_verification: "your-google-site-verification-code" 27 | bing_site_verification: "your-bing-site-verification-code" 28 | 29 | # Exclude from processing 30 | exclude: 31 | - README.md 32 | - .gitignore 33 | - .github/ 34 | - node_modules/ 35 | - vendor/ 36 | 37 | # Include files 38 | include: 39 | - _pages 40 | - assets 41 | - sitemap.xml 42 | - favicon.svg 43 | 44 | # Collections 45 | collections: 46 | docs: 47 | output: true 48 | permalink: /:collection/:name/ 49 | 50 | # Default layouts 51 | defaults: 52 | - scope: 53 | path: "" 54 | type: "pages" 55 | values: 56 | layout: "default" 57 | - scope: 58 | path: "_docs" 59 | type: "docs" 60 | values: 61 | layout: "doc" 62 | 63 | # Theme 64 | theme: minima 65 | 66 | # Custom variables 67 | brand_color: "#8B5CF6" 68 | secondary_color: "#A855F7" 69 | accent_color: "#C084FC" 70 | -------------------------------------------------------------------------------- /docs/assets/images/logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | -------------------------------------------------------------------------------- /docs/favicon.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /docs/robots.txt: -------------------------------------------------------------------------------- 1 | User-agent: * 2 | Allow: / 3 | 4 | # Sitemap location 5 | Sitemap: https://yourusername.github.io/BinaryOptionsTools-v2-1/sitemap.xml 6 | 7 | # Allow indexing of all documentation pages 8 | Allow: /index.html 9 | Allow: /python.html 10 | Allow: /javascript.html 11 | Allow: /rust.html 12 | Allow: /api.html 13 | Allow: /examples.html 14 | 15 | # Allow assets 16 | Allow: /assets/ 17 | 18 | # Disallow any temporary or development files 19 | Disallow: /README.md 20 | Disallow: /DEPLOYMENT.md 21 | Disallow: /_config.yml 22 | Disallow: /.nojekyll 23 | -------------------------------------------------------------------------------- /examples/.gitignore: -------------------------------------------------------------------------------- 1 | .venv -------------------------------------------------------------------------------- /examples/javascript/.gitignore: -------------------------------------------------------------------------------- 1 | balance_monitor.js 2 | closed_deals_analysis.js 3 | get_candles_advanced.js 4 | trades.js -------------------------------------------------------------------------------- /examples/javascript/binary-options-tools.node: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ChipaDevTeam/BinaryOptionsTools-v2/739f401208a7160a076bb2349591bc0a081f1fb1/examples/javascript/binary-options-tools.node -------------------------------------------------------------------------------- /examples/javascript/check_win.js: -------------------------------------------------------------------------------- 1 | const { PocketOption } = require('./binary-options-tools.node'); 2 | 3 | async function main(ssid) { 4 | // Initialize the API client 5 | const api = new PocketOption(ssid); 6 | 7 | // Wait for connection to establish 8 | await new Promise(resolve => setTimeout(resolve, 5000)); 9 | 10 | const [orderId, details] = await api.buy("EURUSD_otc", 10, 60); 11 | const results = await api.checkWin(orderId); 12 | // Get balance 13 | console.log(`Balance: ${results.profit}`); 14 | } 15 | 16 | // Check if ssid is provided as command line argument 17 | const ssid = '' 18 | 19 | main(ssid).catch(console.error); -------------------------------------------------------------------------------- /examples/javascript/create_raw_iterator.js: -------------------------------------------------------------------------------- 1 | const { PocketOption } = require('./binary-options-tools.node'); 2 | const { Validator } = require('./binary-options-tools.node'); 3 | 4 | async function main(ssid) { 5 | // Initialize the API client 6 | const api = new PocketOption(ssid); 7 | 8 | // Wait for connection to establish 9 | await new Promise(resolve => setTimeout(resolve, 5000)); 10 | 11 | // Create a validator for price updates 12 | const validator = Validator.regex(/{"price":\d+\.\d+}/); 13 | 14 | try { 15 | // Create an iterator with 5 minute timeout 16 | const stream = api.createRawIterator( 17 | '42["price/subscribe"]', // WebSocket subscription message 18 | validator, 19 | { timeout: 5 * 60 * 1000 } // 5 minutes in milliseconds 20 | ); 21 | 22 | // Process messages as they arrive 23 | for await (const message of stream) { 24 | console.log(`Received message: ${message}`); 25 | } 26 | } catch (error) { 27 | if (error.name === 'TimeoutError') { 28 | console.log("Stream timed out after 5 minutes"); 29 | } else { 30 | console.log(`Error processing stream: ${error}`); 31 | } 32 | } 33 | } 34 | 35 | const ssid = '' 36 | 37 | main(ssid).catch(console.error); -------------------------------------------------------------------------------- /examples/javascript/create_raw_order.js: -------------------------------------------------------------------------------- 1 | const { PocketOption } = require('./binary-options-tools.node'); 2 | const { Validator } = require('./binary-options-tools.node'); 3 | 4 | async function main(ssid) { 5 | // Initialize the API client 6 | const api = new PocketOption(ssid); 7 | 8 | // Wait for connection to establish 9 | await new Promise(resolve => setTimeout(resolve, 5000)); 10 | 11 | // Basic raw order example 12 | try { 13 | const basicValidator = Validator.contains('"status":"success"'); 14 | const basicResponse = await api.createRawOrder( 15 | '42["signals/subscribe"]', 16 | basicValidator 17 | ); 18 | console.log(`Basic raw order response: ${basicResponse}`); 19 | } catch (error) { 20 | console.log(`Basic raw order failed: ${error}`); 21 | } 22 | 23 | // Raw order with timeout example 24 | try { 25 | const timeoutValidator = Validator.regex(/{\"type\":\"signal\",\"data\":.*}/); 26 | const timeoutResponse = await api.createRawOrderWithTimeout( 27 | '42["signals/load"]', 28 | timeoutValidator, 29 | { timeout: 5000 } // 5 seconds 30 | ); 31 | console.log(`Raw order with timeout response: ${timeoutResponse}`); 32 | } catch (error) { 33 | if (error.name === 'TimeoutError') { 34 | console.log("Order timed out after 5 seconds"); 35 | } else { 36 | console.log(`Order with timeout failed: ${error}`); 37 | } 38 | } 39 | 40 | // Raw order with timeout and retry example 41 | try { 42 | const retryValidator = Validator.all([ 43 | Validator.contains('"type":"trade"'), 44 | Validator.contains('"status":"completed"') 45 | ]); 46 | 47 | const retryResponse = await api.createRawOrderWithTimeoutAndRetry( 48 | '42["trade/subscribe"]', 49 | retryValidator, 50 | { timeout: 10000 } // 10 seconds 51 | ); 52 | console.log(`Raw order with retry response: ${retryResponse}`); 53 | } catch (error) { 54 | console.log(`Order with retry failed: ${error}`); 55 | } 56 | } 57 | 58 | // Check if ssid is provided as command line argument 59 | const ssid = '' 60 | 61 | main(ssid).catch(console.error); -------------------------------------------------------------------------------- /examples/javascript/get_balance.js: -------------------------------------------------------------------------------- 1 | const { PocketOption } = require('./binary-options-tools.node'); 2 | 3 | async function main(ssid) { 4 | // Initialize the API client 5 | const api = new PocketOption(ssid); 6 | 7 | // Wait for connection to establish 8 | await new Promise(resolve => setTimeout(resolve, 5000)); 9 | 10 | // Get balance 11 | const balance = await api.balance(); 12 | console.log(`Balance: ${balance}`); 13 | } 14 | 15 | // Check if ssid is provided as command line argument 16 | const ssid = '' 17 | 18 | main(ssid).catch(console.error); -------------------------------------------------------------------------------- /examples/javascript/get_candles.js: -------------------------------------------------------------------------------- 1 | const { PocketOption } = require('./binary-options-tools.node'); 2 | 3 | async function main(ssid) { 4 | // Initialize the API client 5 | const api = new PocketOption(ssid); 6 | 7 | // Wait for connection to establish 8 | await new Promise(resolve => setTimeout(resolve, 5000)); 9 | 10 | // Define time ranges and frames 11 | const times = Array.from({length: 10}, (_, i) => 3600 * (i + 1)); 12 | const timeFrames = [1, 5, 15, 30, 60, 300]; 13 | 14 | // Get candles for each combination 15 | for (const time of times) { 16 | for (const frame of timeFrames) { 17 | const candles = await api.getCandles("EURUSD_otc", 60, time); 18 | console.log(`Candles for time ${time} and frame ${frame}:`, candles); 19 | } 20 | } 21 | } 22 | 23 | // Check if ssid is provided as command line argument 24 | const ssid = '' 25 | 26 | main(ssid).catch(console.error); -------------------------------------------------------------------------------- /examples/javascript/get_deal_end_time.js: -------------------------------------------------------------------------------- 1 | const { PocketOption } = require('./binary-options-tools.node'); 2 | 3 | async function main(ssid) { 4 | // Initialize the API client 5 | const api = new PocketOption(ssid); 6 | 7 | // Wait for connection to establish 8 | await new Promise(resolve => setTimeout(resolve, 5000)); 9 | 10 | try { 11 | // Place a trade to get a trade ID 12 | const [tradeId, _] = await api.buy({ 13 | asset: "EURUSD_otc", 14 | amount: 1.0, 15 | time: 300, 16 | checkWin: false 17 | }); 18 | 19 | console.log(`Placed trade with ID: ${tradeId}`); 20 | 21 | // Get the deal end time 22 | const endTime = await api.getDealEndTime(tradeId); 23 | 24 | if (endTime) { 25 | const date = new Date(endTime * 1000); 26 | console.log(`Trade expires at: ${date.toLocaleString()}`); 27 | 28 | // Calculate time remaining 29 | const now = Math.floor(Date.now() / 1000); 30 | const remaining = endTime - now; 31 | console.log(`Time remaining: ${remaining} seconds`); 32 | } else { 33 | console.log("Could not find end time for trade"); 34 | } 35 | 36 | } catch (error) { 37 | console.log(`Error: ${error}`); 38 | } 39 | } 40 | 41 | // Check if ssid is provided as command line argument 42 | const ssid = '' 43 | main(ssid).catch(console.error); -------------------------------------------------------------------------------- /examples/javascript/history.js: -------------------------------------------------------------------------------- 1 | const { PocketOption } = require('./binary-options-tools.node'); 2 | 3 | 4 | async function main(ssid) { 5 | // Initialize the API client 6 | const api = new PocketOption(ssid); 7 | 8 | // Wait for connection to establish 9 | await new Promise(resolve => setTimeout(resolve, 5000)); 10 | 11 | // Get candles history 12 | const candles = await api.history("EURUSD_otc", 3600); 13 | console.log("Raw Candles:", candles); 14 | 15 | // If you want to use something similar to pandas in JavaScript, 16 | // you could use libraries like 'dataframe-js' or process the raw data 17 | const formattedCandles = candles.map(candle => ({ 18 | time: new Date(candle.time).toISOString(), 19 | open: candle.open, 20 | high: candle.high, 21 | low: candle.low, 22 | close: candle.close, 23 | volume: candle.volume 24 | })); 25 | 26 | console.log("Formatted Candles:", formattedCandles); 27 | } 28 | 29 | // Check if ssid is provided as command line argument 30 | const ssid = '' 31 | 32 | main(ssid).catch(console.error); -------------------------------------------------------------------------------- /examples/javascript/logs.js: -------------------------------------------------------------------------------- 1 | const { PocketOption, startLogs } = require('./binary-options-tools.node'); 2 | 3 | async function main(ssid) { 4 | // Start logs 5 | startLogs({ 6 | path: ".", 7 | level: "DEBUG", 8 | terminal: true // If false then the logs will only be written to the log files 9 | }); 10 | 11 | // Initialize the API client 12 | const api = new PocketOption(ssid); 13 | 14 | // Place buy and sell orders 15 | const [buyId, buyData] = await api.buy({ 16 | asset: "EURUSD_otc", 17 | amount: 1.0, 18 | time: 300, 19 | checkWin: false 20 | }); 21 | 22 | const [sellId, sellData] = await api.sell({ 23 | asset: "EURUSD_otc", 24 | amount: 1.0, 25 | time: 300, 26 | checkWin: false 27 | }); 28 | 29 | console.log(buyId, sellId); 30 | 31 | // Check wins (same as setting checkWin to true in the buy/sell calls) 32 | const buyResult = await api.checkWin(buyId); 33 | const sellResult = await api.checkWin(sellId); 34 | 35 | console.log("Buy trade result:", buyResult.result); 36 | console.log("Buy trade data:", buyResult); 37 | console.log("Sell trade result:", sellResult.result); 38 | console.log("Sell trade data:", sellResult); 39 | } 40 | 41 | // Check if ssid is provided as command line argument 42 | const ssid = '' 43 | main(ssid).catch(console.error); -------------------------------------------------------------------------------- /examples/javascript/payout.js: -------------------------------------------------------------------------------- 1 | const { PocketOption } = require('./binary-options-tools.node'); 2 | 3 | 4 | async function main(ssid) { 5 | // Initialize the API client 6 | const api = new PocketOption(ssid); 7 | 8 | // Wait for connection to establish 9 | await new Promise(resolve => setTimeout(resolve, 5000)); 10 | 11 | // Get payout for all assets 12 | const payouts = await api.payout(); 13 | console.log("All payouts:", payouts); 14 | 15 | // Get payout for specific asset 16 | const eurUsdPayout = await api.payout("EURUSD_otc"); 17 | console.log("EUR/USD payout:", eurUsdPayout); 18 | 19 | // Get multiple specific payouts 20 | const assets = ["EURUSD_otc", "GBPUSD_otc", "USDJPY_otc"]; 21 | const specificPayouts = await Promise.all( 22 | assets.map(asset => api.payout(asset)) 23 | ); 24 | 25 | assets.forEach((asset, index) => { 26 | console.log(`${asset} payout:`, specificPayouts[index]); 27 | }); 28 | } 29 | 30 | // Check if ssid is provided as command line argument 31 | const ssid = '' 32 | 33 | main(ssid).catch(console.error); -------------------------------------------------------------------------------- /examples/javascript/raw_send.js: -------------------------------------------------------------------------------- 1 | const { PocketOption } = require('./binary-options-tools.node'); 2 | 3 | 4 | async function main(ssid) { 5 | // Initialize the API client 6 | const api = new PocketOption(ssid); 7 | 8 | // Wait for connection to establish 9 | await new Promise(resolve => setTimeout(resolve, 5000)); 10 | 11 | try { 12 | // Subscribe to signals 13 | await api.sendRawMessage('42["signals/subscribe"]'); 14 | console.log("Sent signals subscription message"); 15 | 16 | // Subscribe to price updates 17 | await api.sendRawMessage('42["price/subscribe"]'); 18 | console.log("Sent price subscription message"); 19 | 20 | // Custom message example 21 | const customMessage = '42["custom/event",{"param":"value"}]'; 22 | await api.sendRawMessage(customMessage); 23 | console.log(`Sent custom message: ${customMessage}`); 24 | 25 | // Multiple messages in sequence 26 | const messages = [ 27 | '42["chart/subscribe",{"asset":"EURUSD"}]', 28 | '42["trades/subscribe"]', 29 | '42["notifications/subscribe"]' 30 | ]; 31 | 32 | for (const msg of messages) { 33 | await api.sendRawMessage(msg); 34 | console.log(`Sent message: ${msg}`); 35 | await new Promise(resolve => setTimeout(resolve, 1000)); // 1 second delay 36 | } 37 | 38 | } catch (error) { 39 | console.log(`Error sending message: ${error}`); 40 | } 41 | } 42 | 43 | // Check if ssid is provided as command line argument 44 | const ssid = '' 45 | 46 | main(ssid).catch(console.error); -------------------------------------------------------------------------------- /examples/javascript/stream.js: -------------------------------------------------------------------------------- 1 | const { PocketOption } = require('./binary-options-tools.node'); 2 | 3 | 4 | async function main(ssid) { 5 | // Initialize the API client 6 | const api = new PocketOption(ssid); 7 | 8 | // Wait for connection to establish 9 | await new Promise(resolve => setTimeout(resolve, 5000)); 10 | 11 | // Subscribe to a symbol stream 12 | const stream = await api.subscribeSymbol("EURUSD_otc"); 13 | 14 | console.log("Starting stream..."); 15 | 16 | // Listen to the stream for 1 minute 17 | const endTime = Date.now() + 60000; // 60 seconds 18 | 19 | try { 20 | for await (const data of stream) { 21 | console.log("Received data:", data); 22 | 23 | if (Date.now() > endTime) { 24 | console.log("Stream time finished"); 25 | break; 26 | } 27 | } 28 | } catch (error) { 29 | console.error("Stream error:", error); 30 | } finally { 31 | // Clean up 32 | await stream.close(); 33 | } 34 | } 35 | 36 | // Check if ssid is provided as command line argument 37 | const ssid = '' 38 | main(ssid).catch(console.error); -------------------------------------------------------------------------------- /examples/javascript/stream_chunked.js: -------------------------------------------------------------------------------- 1 | const { PocketOption } = require('./binary-options-tools.node'); 2 | 3 | 4 | async function main(ssid) { 5 | // Initialize the API client 6 | const api = new PocketOption(ssid); 7 | 8 | // Wait for connection to establish 9 | await new Promise(resolve => setTimeout(resolve, 5000)); 10 | 11 | // Subscribe to a chunked symbol stream 12 | const stream = await api.subscribeSymbolChunked("EURUSD_otc"); 13 | 14 | console.log("Starting chunked stream..."); 15 | 16 | // Listen to the stream for 1 minute 17 | const endTime = Date.now() + 60000; // 60 seconds 18 | 19 | try { 20 | for await (const chunk of stream) { 21 | console.log("Received chunk:", chunk); 22 | console.log("Chunk timestamp:", new Date(chunk.timestamp).toISOString()); 23 | console.log("Chunk data:", chunk.data); 24 | 25 | if (Date.now() > endTime) { 26 | console.log("Stream time finished"); 27 | break; 28 | } 29 | } 30 | } catch (error) { 31 | console.error("Stream error:", error); 32 | } finally { 33 | // Clean up 34 | await stream.close(); 35 | } 36 | } 37 | 38 | // Check if ssid is provided as command line argument 39 | const ssid = '' 40 | 41 | main(ssid).catch(console.error); -------------------------------------------------------------------------------- /examples/javascript/validator.js: -------------------------------------------------------------------------------- 1 | const { Validator } = require('./binary-options-tools.node'); 2 | 3 | // Create validator instances 4 | const none = new Validator(); 5 | const regex = Validator.regex(/([A-Z])\w+/); 6 | const start = Validator.startsWith("Hello"); 7 | const end = Validator.endsWith("Bye"); 8 | const contains = Validator.contains("World"); 9 | const rnot = Validator.not(contains); 10 | 11 | // Modified for better testing - smaller groups with predictable outcomes 12 | const rall = Validator.all([regex, start]); // Will need both capital letter and "Hello" at start 13 | const rany = Validator.any([contains, end]); // Will need either "World" or end with "Bye" 14 | 15 | // Testing each validator 16 | console.log(`None validator: ${none.check('hello')} (Expected: true)`); 17 | 18 | console.log(`Regex validator: ${regex.check('Hello')} (Expected: true)`); 19 | console.log(`Regex validator: ${regex.check('hello')} (Expected: false)`); 20 | 21 | console.log(`Starts_with validator: ${start.check('Hello World')} (Expected: true)`); 22 | console.log(`Starts_with validator: ${start.check('hi World')} (Expected: false)`); 23 | 24 | console.log(`Ends_with validator: ${end.check('Hello Bye')} (Expected: true)`); 25 | console.log(`Ends_with validator: ${end.check('Hello there')} (Expected: false)`); 26 | 27 | console.log(`Contains validator: ${contains.check('Hello World')} (Expected: true)`); 28 | console.log(`Contains validator: ${contains.check('Hello there')} (Expected: false)`); 29 | 30 | console.log(`Not validator: ${rnot.check('Hello World')} (Expected: false)`); 31 | console.log(`Not validator: ${rnot.check('Hello there')} (Expected: true)`); 32 | 33 | // Testing the all validator 34 | console.log(`All validator: ${rall.check('Hello World')} (Expected: true)`); // Starts with "Hello" and has capital 35 | console.log(`All validator: ${rall.check('hello World')} (Expected: false)`); // No capital at start 36 | console.log(`All validator: ${rall.check('Hey there')} (Expected: false)`); // Has capital but doesn't start with "Hello" 37 | 38 | // Testing the any validator 39 | console.log(`Any validator: ${rany.check('Hello World')} (Expected: true)`); // Contains "World" 40 | console.log(`Any validator: ${rany.check('Hello Bye')} (Expected: true)`); // Ends with "Bye" 41 | console.log(`Any validator: ${rany.check('Hello there')} (Expected: false)`); // Neither contains "World" nor ends with "Bye" -------------------------------------------------------------------------------- /examples/python/.gitignore: -------------------------------------------------------------------------------- 1 | .venv 2 | error.log 3 | logs.log -------------------------------------------------------------------------------- /examples/python/async/check_win.py: -------------------------------------------------------------------------------- 1 | from BinaryOptionsToolsV2.pocketoption import PocketOptionAsync 2 | 3 | 4 | import asyncio 5 | # Main part of the code 6 | async def main(ssid: str): 7 | # The api automatically detects if the 'ssid' is for real or demo account 8 | api = PocketOptionAsync(ssid) 9 | (buy_id, _) = await api.buy(asset="EURUSD_otc", amount=1.0, time=15, check_win=False) 10 | (sell_id, _) = await api.sell(asset="EURUSD_otc", amount=1.0, time=300, check_win=False) 11 | print(buy_id, sell_id) 12 | # This is the same as setting checkw_win to true on the api.buy and api.sell functions 13 | buy_data = await api.check_win(buy_id) 14 | print(f"Buy trade result: {buy_data['result']}\nBuy trade data: {buy_data}") 15 | sell_data = await api.check_win(sell_id) 16 | print(f"Sell trade result: {sell_data['result']}\nSell trade data: {sell_data}") 17 | 18 | 19 | 20 | if __name__ == '__main__': 21 | ssid = input('Please enter your ssid: ') 22 | asyncio.run(main(ssid)) 23 | -------------------------------------------------------------------------------- /examples/python/async/create_raw_iterator.py: -------------------------------------------------------------------------------- 1 | from BinaryOptionsToolsV2.pocketoption import PocketOptionAsync 2 | from BinaryOptionsToolsV2.validator import Validator 3 | from datetime import timedelta 4 | 5 | import asyncio 6 | 7 | async def main(ssid: str): 8 | # Initialize the API client 9 | api = PocketOptionAsync(ssid) 10 | await asyncio.sleep(5) # Wait for connection to establish 11 | 12 | # Create a validator for price updates 13 | validator = Validator.regex(r'{"price":\d+\.\d+}') 14 | 15 | # Create an iterator with 5 minute timeout 16 | stream = await api.create_raw_iterator( 17 | '42["price/subscribe"]', # WebSocket subscription message 18 | validator, 19 | timeout=timedelta(minutes=5) 20 | ) 21 | 22 | try: 23 | # Process messages as they arrive 24 | async for message in stream: 25 | print(f"Received message: {message}") 26 | except TimeoutError: 27 | print("Stream timed out after 5 minutes") 28 | except Exception as e: 29 | print(f"Error processing stream: {e}") 30 | 31 | if __name__ == '__main__': 32 | ssid = input('Please enter your ssid: ') 33 | asyncio.run(main(ssid)) -------------------------------------------------------------------------------- /examples/python/async/create_raw_order.py: -------------------------------------------------------------------------------- 1 | from BinaryOptionsToolsV2.pocketoption import PocketOptionAsync 2 | from BinaryOptionsToolsV2.validator import Validator 3 | from datetime import timedelta 4 | 5 | import asyncio 6 | 7 | async def main(ssid: str): 8 | # Initialize the API client 9 | api = PocketOptionAsync(ssid) 10 | await asyncio.sleep(5) # Wait for connection to establish 11 | 12 | # Basic raw order example 13 | try: 14 | validator = Validator.contains('"status":"success"') 15 | response = await api.create_raw_order( 16 | '42["signals/subscribe"]', 17 | validator 18 | ) 19 | print(f"Basic raw order response: {response}") 20 | except Exception as e: 21 | print(f"Basic raw order failed: {e}") 22 | 23 | # Raw order with timeout example 24 | try: 25 | validator = Validator.regex(r'{"type":"signal","data":.*}') 26 | response = await api.create_raw_order_with_timout( 27 | '42["signals/load"]', 28 | validator, 29 | timeout=timedelta(seconds=5) 30 | ) 31 | print(f"Raw order with timeout response: {response}") 32 | except TimeoutError: 33 | print("Order timed out after 5 seconds") 34 | except Exception as e: 35 | print(f"Order with timeout failed: {e}") 36 | 37 | # Raw order with timeout and retry example 38 | try: 39 | # Create a validator that checks for both conditions 40 | validator = Validator.all([ 41 | Validator.contains('"type":"trade"'), 42 | Validator.contains('"status":"completed"') 43 | ]) 44 | 45 | response = await api.create_raw_order_with_timeout_and_retry( 46 | '42["trade/subscribe"]', 47 | validator, 48 | timeout=timedelta(seconds=10) 49 | ) 50 | print(f"Raw order with retry response: {response}") 51 | except Exception as e: 52 | print(f"Order with retry failed: {e}") 53 | 54 | if __name__ == '__main__': 55 | ssid = input('Please enter your ssid: ') 56 | asyncio.run(main(ssid)) -------------------------------------------------------------------------------- /examples/python/async/get_balance.py: -------------------------------------------------------------------------------- 1 | from BinaryOptionsToolsV2.pocketoption import PocketOptionAsync 2 | 3 | import asyncio 4 | # Main part of the code 5 | async def main(ssid: str): 6 | # The api automatically detects if the 'ssid' is for real or demo account 7 | api = PocketOptionAsync(ssid) 8 | await asyncio.sleep(5) 9 | 10 | balance = await api.balance() 11 | print(f"Balance: {balance}") 12 | 13 | if __name__ == '__main__': 14 | ssid = input('Please enter your ssid: ') 15 | asyncio.run(main(ssid)) 16 | -------------------------------------------------------------------------------- /examples/python/async/get_candles.py: -------------------------------------------------------------------------------- 1 | from BinaryOptionsToolsV2.pocketoption import PocketOptionAsync 2 | 3 | import pandas as pd 4 | import asyncio 5 | # Main part of the code 6 | async def main(ssid: str): 7 | # The api automatically detects if the 'ssid' is for real or demo account 8 | api = PocketOptionAsync(ssid) 9 | await asyncio.sleep(5) 10 | 11 | # Candles are returned in the format of a list of dictionaries 12 | times = [ 3600 * i for i in range(1, 11)] 13 | time_frames = [ 1, 5, 15, 30, 60, 300] 14 | for time in times: 15 | for frame in time_frames: 16 | 17 | candles = await api.get_candles("EURUSD_otc", 60, time) 18 | # print(f"Raw Candles: {candles}") 19 | candles_pd = pd.DataFrame.from_dict(candles) 20 | print(f"Candles: {candles_pd}") 21 | 22 | if __name__ == '__main__': 23 | ssid = input('Please enter your ssid: ') 24 | asyncio.run(main(ssid)) 25 | 26 | -------------------------------------------------------------------------------- /examples/python/async/get_open_and_close_trades.py: -------------------------------------------------------------------------------- 1 | from BinaryOptionsToolsV2.pocketoption import PocketOptionAsync 2 | 3 | import asyncio 4 | # Main part of the code 5 | async def main(ssid: str): 6 | # The api automatically detects if the 'ssid' is for real or demo account 7 | api = PocketOptionAsync(ssid) 8 | _ = await api.buy(asset="EURUSD_otc", amount=1.0, time=60, check_win=False) 9 | _ = await api.sell(asset="EURUSD_otc", amount=1.0, time=60, check_win=False) 10 | # This is the same as setting checkw_win to true on the api.buy and api.sell functions 11 | opened_deals = await api.opened_deals() 12 | print(f"Opened deals: {opened_deals}\nNumber of opened deals: {len(opened_deals)} (should be at least 2)") 13 | await asyncio.sleep(62) # Wait for the trades to complete 14 | closed_deals = await api.closed_deals() 15 | print(f"Closed deals: {closed_deals}\nNumber of closed deals: {len(closed_deals)} (should be at least 2)") 16 | 17 | 18 | if __name__ == '__main__': 19 | ssid = input('Please enter your ssid: ') 20 | asyncio.run(main(ssid)) 21 | -------------------------------------------------------------------------------- /examples/python/async/history.py: -------------------------------------------------------------------------------- 1 | from BinaryOptionsToolsV2.pocketoption import PocketOptionAsync 2 | 3 | import pandas as pd 4 | import asyncio 5 | # Main part of the code 6 | async def main(ssid: str): 7 | # The api automatically detects if the 'ssid' is for real or demo account 8 | api = PocketOptionAsync(ssid) 9 | await asyncio.sleep(5) 10 | 11 | # Candles are returned in the format of a list of dictionaries 12 | candles = await api.history("EURUSD_otc", 3600) 13 | print(f"Raw Candles: {candles}") 14 | candles_pd = pd.DataFrame.from_dict(candles) 15 | print(f"Candles: {candles_pd}") 16 | 17 | if __name__ == '__main__': 18 | ssid = input('Please enter your ssid: ') 19 | asyncio.run(main(ssid)) 20 | -------------------------------------------------------------------------------- /examples/python/async/log_iterator.py: -------------------------------------------------------------------------------- 1 | # Import necessary modules 2 | from BinaryOptionsToolsV2.tracing import Logger, LogBuilder 3 | from datetime import timedelta 4 | import asyncio 5 | 6 | async def main(): 7 | """ 8 | Main asynchronous function demonstrating the usage of logging system. 9 | """ 10 | 11 | # Create a Logger instance 12 | logger = Logger() 13 | 14 | # Create a LogBuilder instance 15 | log_builder = LogBuilder() 16 | 17 | # Create a new logs iterator with INFO level and 10-second timeout 18 | log_iterator = log_builder.create_logs_iterator(level="INFO", timeout=timedelta(seconds=10)) 19 | 20 | # Configure logging to write to a file 21 | # This will create or append to 'logs.log' file with INFO level logs 22 | log_builder.log_file(path="app_logs.txt", level="INFO") 23 | 24 | # Configure terminal logging for DEBUG level 25 | log_builder.terminal(level="DEBUG") 26 | 27 | # Build and initialize the logging configuration 28 | log_builder.build() 29 | 30 | # Create a Logger instance with the built configuration 31 | logger = Logger() 32 | 33 | # Log some messages at different levels 34 | logger.debug("This is a debug message") 35 | logger.info("This is an info message") 36 | logger.warn("This is a warning message") 37 | logger.error("This is an error message") 38 | 39 | # Example of logging with variables 40 | asset = "EURUSD" 41 | amount = 100 42 | logger.info(f"Bought {amount} units of {asset}") 43 | 44 | # Demonstrate async usage 45 | async def log_async(): 46 | """ 47 | Asynchronous logging function demonstrating async usage. 48 | """ 49 | logger.debug("This is an asynchronous debug message") 50 | await asyncio.sleep(5) # Simulate some work 51 | logger.info("Async operation completed") 52 | 53 | # Run the async function 54 | task1 = asyncio.create_task(log_async()) 55 | 56 | # Example of using LogBuilder for creating iterators 57 | async def process_logs(log_iterator): 58 | """ 59 | Function demonstrating the use of LogSubscription. 60 | """ 61 | 62 | try: 63 | async for log in log_iterator: 64 | print(f"Received log: {log}") 65 | # Each log is a dict so we can access the message 66 | print(f"Log message: {log['message']}") 67 | except Exception as e: 68 | print(f"Error processing logs: {e}") 69 | 70 | # Run the logs processing function 71 | task2 = asyncio.create_task(process_logs(log_iterator)) 72 | 73 | # Execute both tasks at the same time 74 | await asyncio.gather(task1, task2) 75 | 76 | 77 | 78 | if __name__ == "__main__": 79 | asyncio.run(main()) -------------------------------------------------------------------------------- /examples/python/async/logs.py: -------------------------------------------------------------------------------- 1 | from BinaryOptionsToolsV2.tracing import start_logs 2 | from BinaryOptionsToolsV2.pocketoption import PocketOptionAsync 3 | 4 | import asyncio 5 | # Main part of the code 6 | async def main(ssid: str): 7 | # Start logs, it works perfectly on async code 8 | start_logs(path=".", level="DEBUG", terminal=True) # If false then the logs will only be written to the log files 9 | # The api automatically detects if the 'ssid' is for real or demo account 10 | api = PocketOptionAsync(ssid) 11 | (buy_id, _) = await api.buy(asset="EURUSD_otc", amount=1.0, time=300, check_win=False) 12 | (sell_id, _) = await api.sell(asset="EURUSD_otc", amount=1.0, time=300, check_win=False) 13 | print(buy_id, sell_id) 14 | # This is the same as setting checkw_win to true on the api.buy and api.sell functions 15 | buy_data = await api.check_win(buy_id) 16 | sell_data = await api.check_win(sell_id) 17 | print(f"Buy trade result: {buy_data['result']}\nBuy trade data: {buy_data}") 18 | print(f"Sell trade result: {sell_data['result']}\nSell trade data: {sell_data}") 19 | 20 | 21 | 22 | if __name__ == '__main__': 23 | ssid = input('Please enter your ssid: ') 24 | asyncio.run(main(ssid)) 25 | -------------------------------------------------------------------------------- /examples/python/async/payout.py: -------------------------------------------------------------------------------- 1 | from BinaryOptionsToolsV2.pocketoption import PocketOptionAsync 2 | 3 | import asyncio 4 | # Main part of the code 5 | async def main(ssid: str): 6 | # The api automatically detects if the 'ssid' is for real or demo account 7 | api = PocketOptionAsync(ssid) 8 | await asyncio.sleep(5) 9 | 10 | # Candñes are returned in the format of a list of dictionaries 11 | full_payout = await api.payout() # Returns a dictionary asset: payout 12 | print(f"Full Payout: {full_payout}") 13 | partial_payout = await api.payout(["EURUSD_otc", "EURUSD", "AEX25"]) # Returns a list of the payout for each of the passed assets in order 14 | print(f"Partial Payout: {partial_payout}") 15 | single_payout = await api.payout("EURUSD_otc") # Returns the payout for the specified asset 16 | print(f"Single Payout: {single_payout}") 17 | 18 | 19 | if __name__ == '__main__': 20 | ssid = input('Please enter your ssid: ') 21 | asyncio.run(main(ssid)) 22 | -------------------------------------------------------------------------------- /examples/python/async/raw_send.py: -------------------------------------------------------------------------------- 1 | from BinaryOptionsToolsV2.pocketoption import PocketOptionAsync 2 | import asyncio 3 | 4 | async def main(ssid: str): 5 | # Initialize the API client 6 | api = PocketOptionAsync(ssid) 7 | await asyncio.sleep(5) # Wait for connection to establish 8 | 9 | # Example of sending a raw message 10 | try: 11 | # Subscribe to signals 12 | await api.send_raw_message('42["signals/subscribe"]') 13 | print("Sent signals subscription message") 14 | 15 | # Subscribe to price updates 16 | await api.send_raw_message('42["price/subscribe"]') 17 | print("Sent price subscription message") 18 | 19 | # Custom message example 20 | custom_message = '42["custom/event",{"param":"value"}]' 21 | await api.send_raw_message(custom_message) 22 | print(f"Sent custom message: {custom_message}") 23 | 24 | # Multiple messages in sequence 25 | messages = [ 26 | '42["chart/subscribe",{"asset":"EURUSD"}]', 27 | '42["trades/subscribe"]', 28 | '42["notifications/subscribe"]' 29 | ] 30 | 31 | for msg in messages: 32 | await api.send_raw_message(msg) 33 | print(f"Sent message: {msg}") 34 | await asyncio.sleep(1) # Small delay between messages 35 | 36 | except Exception as e: 37 | print(f"Error sending message: {e}") 38 | 39 | if __name__ == '__main__': 40 | ssid = input('Please enter your ssid: ') 41 | 42 | -------------------------------------------------------------------------------- /examples/python/async/subscribe_symbol.py: -------------------------------------------------------------------------------- 1 | from BinaryOptionsToolsV2.pocketoption import PocketOptionAsync 2 | 3 | import asyncio 4 | # Main part of the code 5 | async def main(ssid: str): 6 | # The api automatically detects if the 'ssid' is for real or demo account 7 | api = PocketOptionAsync(ssid) 8 | stream = await api.subscribe_symbol("EURUSD_otc") 9 | 10 | # This should run forever so you will need to force close the program 11 | async for candle in stream: 12 | print(f"Candle: {candle}") # Each candle is in format of a dictionary 13 | 14 | if __name__ == '__main__': 15 | ssid = input('Please enter your ssid: ') 16 | asyncio.run(main(ssid)) 17 | -------------------------------------------------------------------------------- /examples/python/async/subscribe_symbol_chuncked.py: -------------------------------------------------------------------------------- 1 | from BinaryOptionsToolsV2.pocketoption import PocketOptionAsync 2 | 3 | import asyncio 4 | # Main part of the code 5 | async def main(ssid: str): 6 | # The api automatically detects if the 'ssid' is for real or demo account 7 | api = PocketOptionAsync(ssid) 8 | stream = await api.subscribe_symbol_chuncked("EURUSD_otc", 15) # Returns a candle obtained from combining 15 (chunk_size) candles 9 | 10 | # This should run forever so you will need to force close the program 11 | async for candle in stream: 12 | print(f"Candle: {candle}") # Each candle is in format of a dictionary 13 | 14 | if __name__ == '__main__': 15 | ssid = input('Please enter your ssid: ') 16 | asyncio.run(main(ssid)) 17 | -------------------------------------------------------------------------------- /examples/python/async/subscribe_symbol_timed.py: -------------------------------------------------------------------------------- 1 | from BinaryOptionsToolsV2.pocketoption import PocketOptionAsync 2 | from BinaryOptionsToolsV2.tracing import start_logs 3 | from datetime import timedelta 4 | 5 | import asyncio 6 | 7 | # Main part of the code 8 | async def main(ssid: str): 9 | # The api automatically detects if the 'ssid' is for real or demo account 10 | start_logs(".", "INFO") 11 | api = PocketOptionAsync(ssid) 12 | stream = await api.subscribe_symbol_timed("EURUSD_otc", timedelta(seconds=5)) # Returns a candle obtained from combining candles that are inside a specific time range 13 | 14 | # This should run forever so you will need to force close the program 15 | async for candle in stream: 16 | print(f"Candle: {candle}") # Each candle is in format of a dictionary 17 | 18 | if __name__ == '__main__': 19 | ssid = input('Please enter your ssid: ') 20 | asyncio.run(main(ssid)) 21 | -------------------------------------------------------------------------------- /examples/python/async/trade.py: -------------------------------------------------------------------------------- 1 | from BinaryOptionsToolsV2.pocketoption import PocketOptionAsync 2 | 3 | import asyncio 4 | # Main part of the code 5 | async def main(ssid: str): 6 | # The api automatically detects if the 'ssid' is for real or demo account 7 | api = PocketOptionAsync(ssid) 8 | 9 | (buy_id, buy) = await api.buy(asset="EURUSD_otc", amount=1.0, time=60, check_win=False) 10 | print(f"Buy trade id: {buy_id}\nBuy trade data: {buy}") 11 | (sell_id, sell) = await api.sell(asset="EURUSD_otc", amount=1.0, time=60, check_win=False) 12 | print(f"Sell trade id: {sell_id}\nSell trade data: {sell}") 13 | 14 | if __name__ == '__main__': 15 | ssid = input('Please enter your ssid: ') 16 | asyncio.run(main(ssid)) 17 | -------------------------------------------------------------------------------- /examples/python/async/validator.py: -------------------------------------------------------------------------------- 1 | from BinaryOptionsToolsV2.validator import Validator 2 | 3 | if __name__ == "__main__": 4 | none = Validator() 5 | regex = Validator.regex("([A-Z])\w+") 6 | start = Validator.starts_with("Hello") 7 | end = Validator.ends_with("Bye") 8 | contains = Validator.contains("World") 9 | rnot = Validator.ne(contains) 10 | custom = Validator.custom(lambda x: x.startswith("Hello") and x.endswith("World")) 11 | 12 | # Modified for better testing - smaller groups with predictable outcomes 13 | rall = Validator.all([regex, start]) # Will need both capital letter and "Hello" at start 14 | rany = Validator.any([contains, end]) # Will need either "World" or end with "Bye" 15 | 16 | print(f"None validator: {none.check('hello')} (Expected: True)") 17 | print(f"Regex validator: {regex.check('Hello')} (Expected: True)") 18 | print(f"Regex validator: {regex.check('hello')} (Expected: False)") 19 | print(f"Starts_with validator: {start.check('Hello World')} (Expected: True)") 20 | print(f"Starts_with validator: {start.check('hi World')} (Expected: False)") 21 | print(f"Ends_with validator: {end.check('Hello Bye')} (Expected: True)") 22 | print(f"Ends_with validator: {end.check('Hello there')} (Expected: False)") 23 | print(f"Contains validator: {contains.check('Hello World')} (Expected: True)") 24 | print(f"Contains validator: {contains.check('Hello there')} (Expected: False)") 25 | print(f"Not validator: {rnot.check('Hello World')} (Expected: False)") 26 | print(f"Not validator: {rnot.check('Hello there')} (Expected: True)") 27 | try: 28 | print(f"Custom validator: {custom.check('Hello World')}, (Expected: True)") 29 | print(f"Custom validator: {custom.check('Hello there')}, (Expected: False)") 30 | except Exception as e: 31 | print(f"Error: {e}") 32 | # Testing the all validator 33 | print(f"All validator: {rall.check('Hello World')} (Expected: True)") # Starts with "Hello" and has capital 34 | print(f"All validator: {rall.check('hello World')} (Expected: False)") # No capital at start 35 | print(f"All validator: {rall.check('Hey there')} (Expected: False)") # Has capital but doesn't start with "Hello" 36 | 37 | # Testing the any validator 38 | print(f"Any validator: {rany.check('Hello World')} (Expected: True)") # Contains "World" 39 | print(f"Any validator: {rany.check('Hello Bye')} (Expected: True)") # Ends with "Bye" 40 | print(f"Any validator: {rany.check('Hello there')} (Expected: False)") # Neither contains "World" nor ends with "Bye" -------------------------------------------------------------------------------- /examples/python/sync/check_win.py: -------------------------------------------------------------------------------- 1 | from BinaryOptionsToolsV2.pocketoption import PocketOption 2 | 3 | # Main part of the code 4 | def main(ssid: str): 5 | # The api automatically detects if the 'ssid' is for real or demo account 6 | api = PocketOption(ssid) 7 | (buy_id, _) = api.buy(asset="EURUSD_otc", amount=1.0, time=60, check_win=False) 8 | (sell_id, _) = api.sell(asset="EURUSD_otc", amount=1.0, time=60, check_win=False) 9 | # This is the same as setting checkw_win to true on the api.buy and api.sell functions 10 | buy_data = api.check_win(buy_id) 11 | sell_data = api.check_win(sell_id) 12 | print(f"Buy trade result: {buy_data['result']}\nBuy trade data: {buy_data}") 13 | print(f"Sell trade result: {sell_data['result']}\nSell trade data: {sell_data}") 14 | 15 | 16 | 17 | if __name__ == '__main__': 18 | ssid = input('Please enter your ssid: ') 19 | main(ssid) 20 | -------------------------------------------------------------------------------- /examples/python/sync/create_raw_iterator.py: -------------------------------------------------------------------------------- 1 | from BinaryOptionsToolsV2.pocketoption import PocketOption 2 | from BinaryOptionsToolsV2.validator import Validator 3 | from datetime import timedelta 4 | import time 5 | 6 | def main(ssid: str): 7 | # Initialize the API client 8 | api = PocketOption(ssid) 9 | time.sleep(5) # Wait for connection to establish 10 | 11 | # Create a validator for price updates 12 | validator = Validator.regex(r'{"price":\d+\.\d+}') 13 | 14 | # Create an iterator with 5 minute timeout 15 | stream = api.create_raw_iterator( 16 | '42["price/subscribe"]', # WebSocket subscription message 17 | validator, 18 | timeout=timedelta(minutes=5) 19 | ) 20 | 21 | try: 22 | # Process messages as they arrive 23 | for message in stream: 24 | print(f"Received message: {message}") 25 | except TimeoutError: 26 | print("Stream timed out after 5 minutes") 27 | except Exception as e: 28 | print(f"Error processing stream: {e}") 29 | 30 | if __name__ == '__main__': 31 | ssid = input('Please enter your ssid: ') 32 | main(ssid) -------------------------------------------------------------------------------- /examples/python/sync/create_raw_order.py: -------------------------------------------------------------------------------- 1 | from BinaryOptionsToolsV2.pocketoption import PocketOption 2 | from BinaryOptionsToolsV2.validator import Validator 3 | from datetime import timedelta 4 | import time 5 | 6 | def main(ssid: str): 7 | # Initialize the API client 8 | api = PocketOption(ssid) 9 | time.sleep(5) # Wait for connection to establish 10 | 11 | # Basic raw order example 12 | try: 13 | validator = Validator.contains('"status":"success"') 14 | response = api.create_raw_order( 15 | '42["signals/subscribe"]', 16 | validator 17 | ) 18 | print(f"Basic raw order response: {response}") 19 | except Exception as e: 20 | print(f"Basic raw order failed: {e}") 21 | 22 | # Raw order with timeout example 23 | try: 24 | validator = Validator.regex(r'{"type":"signal","data":.*}') 25 | response = api.create_raw_order_with_timout( 26 | '42["signals/load"]', 27 | validator, 28 | timeout=timedelta(seconds=5) 29 | ) 30 | print(f"Raw order with timeout response: {response}") 31 | except TimeoutError: 32 | print("Order timed out after 5 seconds") 33 | except Exception as e: 34 | print(f"Order with timeout failed: {e}") 35 | 36 | # Raw order with timeout and retry example 37 | try: 38 | # Create a validator that checks for both conditions 39 | validator = Validator.all([ 40 | Validator.contains('"type":"trade"'), 41 | Validator.contains('"status":"completed"') 42 | ]) 43 | 44 | response = api.create_raw_order_with_timeout_and_retry( 45 | '42["trade/subscribe"]', 46 | validator, 47 | timeout=timedelta(seconds=10) 48 | ) 49 | print(f"Raw order with retry response: {response}") 50 | except Exception as e: 51 | print(f"Order with retry failed: {e}") 52 | 53 | if __name__ == '__main__': 54 | ssid = input('Please enter your ssid: ') 55 | main(ssid) -------------------------------------------------------------------------------- /examples/python/sync/get_balance.py: -------------------------------------------------------------------------------- 1 | from BinaryOptionsToolsV2.pocketoption import PocketOption 2 | 3 | import time 4 | # Main part of the code 5 | def main(ssid: str): 6 | # The api automatically detects if the 'ssid' is for real or demo account 7 | api = PocketOption(ssid) 8 | time.sleep(5) 9 | 10 | balance = api.balance() 11 | print(f"Balance: {balance}") 12 | 13 | if __name__ == '__main__': 14 | ssid = input('Please enter your ssid: ') 15 | main(ssid) 16 | -------------------------------------------------------------------------------- /examples/python/sync/get_candles.py: -------------------------------------------------------------------------------- 1 | from BinaryOptionsToolsV2.pocketoption import PocketOption 2 | 3 | import pandas as pd 4 | import time 5 | # Main part of the code 6 | def main(ssid: str): 7 | # The api automatically detects if the 'ssid' is for real or demo account 8 | api = PocketOption(ssid) 9 | time.sleep(5) 10 | 11 | # Candñes are returned in the format of a list of dictionaries 12 | candles = api.get_candles("EURUSD_otc", 60, 3600) 13 | print(f"Raw Candles: {candles}") 14 | candles_pd = pd.DataFrame.from_dict(candles) 15 | print(f"Candles: {candles_pd}") 16 | 17 | if __name__ == '__main__': 18 | ssid = input('Please enter your ssid: ') 19 | main(ssid) 20 | -------------------------------------------------------------------------------- /examples/python/sync/get_open_and_close_trades.py: -------------------------------------------------------------------------------- 1 | from BinaryOptionsToolsV2.pocketoption import PocketOption 2 | 3 | import time 4 | # Main part of the code 5 | def main(ssid: str): 6 | # The api automatically detects if the 'ssid' is for real or demo account 7 | api = PocketOption(ssid) 8 | _ = api.buy(asset="EURUSD_otc", amount=1.0, time=60, check_win=False) 9 | _ = api.sell(asset="EURUSD_otc", amount=1.0, time=60, check_win=False) 10 | # This is the same as setting checkw_win to true on the api.buy and api.sell functions 11 | opened_deals = api.opened_deals() 12 | time.sleep(62) # Wait for the trades to complete 13 | closed_deals = api.closed_deals() 14 | print(f"Opened deals: {opened_deals}\nNumber of opened deals: {len(opened_deals)} (should be at least 2)") 15 | print(f"Closed deals: {closed_deals}\nNumber of closed deals: {len(closed_deals)} (should be at least 2)") 16 | 17 | 18 | if __name__ == '__main__': 19 | ssid = input('Please enter your ssid: ') 20 | main(ssid) 21 | -------------------------------------------------------------------------------- /examples/python/sync/history.py: -------------------------------------------------------------------------------- 1 | from BinaryOptionsToolsV2.pocketoption import PocketOption 2 | 3 | import pandas as pd 4 | import time 5 | # Main part of the code 6 | def main(ssid: str): 7 | # The api automatically detects if the 'ssid' is for real or demo account 8 | api = PocketOption(ssid) 9 | time.sleep(5) 10 | 11 | # Candles are returned in the format of a list of dictionaries 12 | candles = api.history("EURUSD_otc", 3600) 13 | print(f"Raw Candles: {candles}") 14 | candles_pd = pd.DataFrame.from_dict(candles) 15 | print(f"Candles: {candles_pd}") 16 | 17 | if __name__ == '__main__': 18 | ssid = input('Please enter your ssid: ') 19 | main(ssid) 20 | -------------------------------------------------------------------------------- /examples/python/sync/log_iterator.py: -------------------------------------------------------------------------------- 1 | # Import necessary modules 2 | from BinaryOptionsToolsV2.tracing import Logger, LogBuilder 3 | from datetime import timedelta 4 | 5 | from multiprocessing import Process 6 | 7 | import time 8 | 9 | def main(): 10 | """ 11 | Main synchronous function demonstrating the usage of logging system. 12 | """ 13 | 14 | # Create a Logger instance 15 | logger = Logger() 16 | 17 | # Create a LogBuilder instance 18 | log_builder = LogBuilder() 19 | 20 | # Create a new logs iterator with INFO level and 10-second timeout 21 | log_iterator = log_builder.create_logs_iterator(level="INFO", timeout=timedelta(seconds=10)) 22 | 23 | # Configure logging to write to a file 24 | # This will create or append to 'logs.log' file with INFO level logs 25 | log_builder.log_file(path="app_logs.txt", level="INFO") 26 | 27 | # Configure terminal logging for DEBUG level 28 | log_builder.terminal(level="DEBUG") 29 | 30 | # Build and initialize the logging configuration 31 | log_builder.build() 32 | 33 | # Create a Logger instance with the built configuration 34 | logger = Logger() 35 | 36 | # Log some messages at different levels 37 | logger.debug("This is a debug message") 38 | logger.info("This is an info message") 39 | logger.warn("This is a warning message") 40 | logger.error("This is an error message") 41 | 42 | # Example of logging with variables 43 | asset = "EURUSD" 44 | amount = 100 45 | logger.info(f"Bought {amount} units of {asset}") 46 | 47 | # Demonstrate sync usage 48 | def log_sync(): 49 | """ 50 | Syncronous logging function demonstrating sync usage. 51 | """ 52 | logger.debug("This is a synchronous debug message") 53 | time.sleep(5) # Simulate some work 54 | logger.info("Sync operation completed") 55 | 56 | # Run the sync function 57 | task1 = Process(target=log_sync()) 58 | task1.start() 59 | # Example of using LogBuilder for creating iterators 60 | def process_logs(log_iterator): 61 | """ 62 | Function demonstrating the use of LogSubscription. 63 | """ 64 | 65 | try: 66 | for log in log_iterator: 67 | print(f"Received log: {log}") 68 | # Each log is a dict so we can access the message 69 | print(f"Log message: {log['message']}") 70 | except Exception as e: 71 | print(f"Error processing logs: {e}") 72 | 73 | # Run the logs processing function 74 | task2 = Process(target=process_logs(log_iterator)) 75 | task2.start() 76 | # Execute both tasks at the same time 77 | task1.join() 78 | task2.join() 79 | 80 | 81 | 82 | if __name__ == "__main__": 83 | main() -------------------------------------------------------------------------------- /examples/python/sync/logs.py: -------------------------------------------------------------------------------- 1 | from BinaryOptionsToolsV2.tracing import start_logs 2 | from BinaryOptionsToolsV2.pocketoption import PocketOption 3 | 4 | # Main part of the code 5 | def main(ssid: str): 6 | # Start logs, it works perfectly on sync code 7 | start_logs(path=".", level="DEBUG", terminal=True) # If false then the logs will only be written to the log files 8 | # The api automatically detects if the 'ssid' is for real or demo account 9 | api = PocketOption(ssid) 10 | (buy_id, _) = api.buy(asset="EURUSD_otc", amount=1.0, time=300, check_win=False) 11 | (sell_id, _) = api.sell(asset="EURUSD_otc", amount=1.0, time=300, check_win=False) 12 | print(buy_id, sell_id) 13 | # This is the same as setting checkw_win to true on the api.buy and api.sell functions 14 | buy_data = api.check_win(buy_id) 15 | sell_data = api.check_win(sell_id) 16 | print(f"Buy trade result: {buy_data['result']}\nBuy trade data: {buy_data}") 17 | print(f"Sell trade result: {sell_data['result']}\nSell trade data: {sell_data}") 18 | 19 | 20 | 21 | if __name__ == '__main__': 22 | ssid = input('Please enter your ssid: ') 23 | main(ssid) 24 | -------------------------------------------------------------------------------- /examples/python/sync/payout.py: -------------------------------------------------------------------------------- 1 | from BinaryOptionsToolsV2.pocketoption import PocketOption 2 | 3 | import time 4 | # Main part of the code 5 | def main(ssid: str): 6 | # The api automatically detects if the 'ssid' is for real or demo account 7 | api = PocketOption(ssid) 8 | time.sleep(5) 9 | 10 | # Candñes are returned in the format of a list of dictionaries 11 | full_payout = api.payout() # Returns a dictionary asset: payout 12 | print(f"Full Payout: {full_payout}") 13 | partial_payout = api.payout(["EURUSD_otc", "EURUSD", "AEX25"]) # Returns a list of the payout for each of the passed assets in order 14 | print(f"Partial Payout: {partial_payout}") 15 | single_payout = api.payout("EURUSD_otc") # Returns the payout for the specified asset 16 | print(f"Single Payout: {single_payout}") 17 | 18 | 19 | if __name__ == '__main__': 20 | ssid = input('Please enter your ssid: ') 21 | main(ssid) 22 | -------------------------------------------------------------------------------- /examples/python/sync/raw_send.py: -------------------------------------------------------------------------------- 1 | from BinaryOptionsToolsV2.pocketoption import PocketOption 2 | import time 3 | 4 | def main(ssid: str): 5 | # Initialize the API client 6 | api = PocketOption(ssid) 7 | time.sleep(5) # Wait for connection to establish 8 | 9 | # Example of sending a raw message 10 | try: 11 | # Subscribe to signals 12 | api.raw_send('42["signals/subscribe"]') 13 | print("Sent signals subscription message") 14 | 15 | # Subscribe to price updates 16 | api.raw_send('42["price/subscribe"]') 17 | print("Sent price subscription message") 18 | 19 | # Custom message example 20 | custom_message = '42["custom/event",{"param":"value"}]' 21 | api.raw_send(custom_message) 22 | print(f"Sent custom message: {custom_message}") 23 | 24 | except Exception as e: 25 | print(f"Error sending message: {e}") 26 | 27 | if __name__ == '__main__': 28 | ssid = input('Please enter your ssid: ') 29 | 30 | -------------------------------------------------------------------------------- /examples/python/sync/subscribe_symbol.py: -------------------------------------------------------------------------------- 1 | from BinaryOptionsToolsV2.pocketoption import PocketOption 2 | 3 | # Main part of the code 4 | def main(ssid: str): 5 | # The api automatically detects if the 'ssid' is for real or demo account 6 | api = PocketOption(ssid) 7 | stream = api.subscribe_symbol("EURUSD_otc") 8 | 9 | # This should run forever so you will need to force close the program 10 | for candle in stream: 11 | print(f"Candle: {candle}") # Each candle is in format of a dictionary 12 | 13 | if __name__ == '__main__': 14 | ssid = input('Please enter your ssid: ') 15 | main(ssid) 16 | -------------------------------------------------------------------------------- /examples/python/sync/subscribe_symbol_chuncked.py: -------------------------------------------------------------------------------- 1 | from BinaryOptionsToolsV2.pocketoption import PocketOption 2 | 3 | # Main part of the code 4 | def main(ssid: str): 5 | # The api automatically detects if the 'ssid' is for real or demo account 6 | api = PocketOption(ssid) 7 | stream = api.subscribe_symbol_chuncked("EURUSD_otc", 15) # Returns a candle obtained from combining 15 (chunk_size) candles 8 | 9 | # This should run forever so you will need to force close the program 10 | for candle in stream: 11 | print(f"Candle: {candle}") # Each candle is in format of a dictionary 12 | 13 | if __name__ == '__main__': 14 | ssid = input('Please enter your ssid: ') 15 | main(ssid) 16 | -------------------------------------------------------------------------------- /examples/python/sync/subscribe_symbol_timed.py: -------------------------------------------------------------------------------- 1 | from BinaryOptionsToolsV2.pocketoption import PocketOption 2 | from datetime import timedelta 3 | 4 | 5 | # Main part of the code 6 | def main(ssid: str): 7 | # The api automatically detects if the 'ssid' is for real or demo account 8 | api = PocketOption(ssid) 9 | stream = api.subscribe_symbol_timed("EURUSD_otc", timedelta(seconds=15)) # Returns a candle obtained from combining candles that are inside a specific time range 10 | 11 | # This should run forever so you will need to force close the program 12 | for candle in stream: 13 | print(f"Candle: {candle}") # Each candle is in format of a dictionary 14 | 15 | if __name__ == '__main__': 16 | ssid = input('Please enter your ssid: ') 17 | main(ssid) 18 | -------------------------------------------------------------------------------- /examples/python/sync/trade.py: -------------------------------------------------------------------------------- 1 | from BinaryOptionsToolsV2.pocketoption import PocketOption 2 | 3 | # Main part of the code 4 | def main(ssid: str): 5 | # The api automatically detects if the 'ssid' is for real or demo account 6 | api = PocketOption(ssid) 7 | 8 | (buy_id, buy) = api.buy(asset="EURUSD_otc", amount=1.0, time=60, check_win=False) 9 | print(f"Buy trade id: {buy_id}\nBuy trade data: {buy}") 10 | (sell_id, sell) = api.sell(asset="EURUSD_otc", amount=1.0, time=60, check_win=False) 11 | print(f"Sell trade id: {sell_id}\nSell trade data: {sell}") 12 | 13 | if __name__ == '__main__': 14 | ssid = input('Please enter your ssid: ') 15 | main(ssid) 16 | -------------------------------------------------------------------------------- /examples/python/sync/validator.py: -------------------------------------------------------------------------------- 1 | # Same thing as in the async folder, the code is sync and can be passed to both the async and sync implementations of the create_raw_order* methods. 2 | 3 | from BinaryOptionsToolsV2.validator import Validator 4 | 5 | if __name__ == "__main__": 6 | none = Validator() 7 | regex = Validator.regex("([A-Z])\w+") 8 | start = Validator.starts_with("Hello") 9 | end = Validator.ends_with("Bye") 10 | contains = Validator.contains("World") 11 | rnot = Validator.ne(contains) 12 | custom = Validator.custom(lambda x: x.startswith("Hello") and x.endswith("World")) 13 | 14 | # Modified for better testing - smaller groups with predictable outcomes 15 | rall = Validator.all([regex, start]) # Will need both capital letter and "Hello" at start 16 | rany = Validator.any([contains, end]) # Will need either "World" or end with "Bye" 17 | 18 | print(f"None validator: {none.check('hello')} (Expected: True)") 19 | print(f"Regex validator: {regex.check('Hello')} (Expected: True)") 20 | print(f"Regex validator: {regex.check('hello')} (Expected: False)") 21 | print(f"Starts_with validator: {start.check('Hello World')} (Expected: True)") 22 | print(f"Starts_with validator: {start.check('hi World')} (Expected: False)") 23 | print(f"Ends_with validator: {end.check('Hello Bye')} (Expected: True)") 24 | print(f"Ends_with validator: {end.check('Hello there')} (Expected: False)") 25 | print(f"Contains validator: {contains.check('Hello World')} (Expected: True)") 26 | print(f"Contains validator: {contains.check('Hello there')} (Expected: False)") 27 | print(f"Not validator: {rnot.check('Hello World')} (Expected: False)") 28 | print(f"Not validator: {rnot.check('Hello there')} (Expected: True)") 29 | try: 30 | print(f"Custom validator: {custom.check('Hello World')}, (Expected: True)") 31 | print(f"Custom validator: {custom.check('Hello there')}, (Expected: False)") 32 | except Exception as e: 33 | print(f"Error: {e}") 34 | # Testing the all validator 35 | print(f"All validator: {rall.check('Hello World')} (Expected: True)") # Starts with "Hello" and has capital 36 | print(f"All validator: {rall.check('hello World')} (Expected: False)") # No capital at start 37 | print(f"All validator: {rall.check('Hey there')} (Expected: False)") # Has capital but doesn't start with "Hello" 38 | 39 | # Testing the any validator 40 | print(f"Any validator: {rany.check('Hello World')} (Expected: True)") # Contains "World" 41 | print(f"Any validator: {rany.check('Hello Bye')} (Expected: True)") # Ends with "Bye" 42 | print(f"Any validator: {rany.check('Hello there')} (Expected: False)") # Neither contains "World" nor ends with "Bye" -------------------------------------------------------------------------------- /logs/errors.log: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ChipaDevTeam/BinaryOptionsTools-v2/739f401208a7160a076bb2349591bc0a081f1fb1/logs/errors.log -------------------------------------------------------------------------------- /tests/assets.txt: -------------------------------------------------------------------------------- 1 | #AAPL 2 | #AAPL_otc 3 | #AXP 4 | #AXP_otc 5 | #BA 6 | #BA_otc 7 | #CSCO 8 | #CSCO_otc 9 | #FB 10 | #FB_otc 11 | #INTC 12 | #INTC_otc 13 | #JNJ 14 | #JNJ_otc 15 | #JPM 16 | #MCD 17 | #MCD_otc 18 | #MSFT 19 | #MSFT_otc 20 | #PFE 21 | #PFE_otc 22 | #TSLA 23 | #TSLA_otc 24 | #XOM 25 | #XOM_otc 26 | 100GBP 27 | 100GBP_otc 28 | ADA-USD_otc 29 | AEDCNY_otc 30 | AEX25 31 | AMZN_otc 32 | AUDCAD 33 | AUDCAD_otc 34 | AUDCHF 35 | AUDCHF_otc 36 | AUDJPY 37 | AUDJPY_otc 38 | AUDNZD_otc 39 | AUDUSD 40 | AUDUSD_otc 41 | AUS200 42 | AUS200_otc 43 | AVAX_otc 44 | BABA 45 | BABA_otc 46 | BCHEUR 47 | BCHGBP 48 | BCHJPY 49 | BHDCNY_otc 50 | BITB_otc 51 | BNB-USD_otc 52 | BTCGBP 53 | BTCJPY 54 | BTCUSD 55 | BTCUSD_otc 56 | CAC40 57 | CADCHF 58 | CADCHF_otc 59 | CADJPY 60 | CADJPY_otc 61 | CHFJPY 62 | CHFJPY_otc 63 | CHFNOK_otc 64 | CITI 65 | CITI_otc 66 | D30EUR 67 | D30EUR_otc 68 | DASH_USD 69 | DJI30 70 | DJI30_otc 71 | DOGE_otc 72 | DOTUSD_otc 73 | E35EUR 74 | E35EUR_otc 75 | E50EUR 76 | E50EUR_otc 77 | ETHUSD 78 | ETHUSD_otc 79 | EURAUD 80 | EURCAD 81 | EURCHF 82 | EURCHF_otc 83 | EURGBP 84 | EURGBP_otc 85 | EURHUF_otc 86 | EURJPY 87 | EURJPY_otc 88 | EURNZD_otc 89 | EURRUB_otc 90 | EURTRY_otc 91 | EURUSD 92 | EURUSD_otc 93 | F40EUR 94 | F40EUR_otc 95 | FDX_otc 96 | GBPAUD 97 | GBPAUD_otc 98 | GBPCAD 99 | GBPCHF 100 | GBPJPY 101 | GBPJPY_otc 102 | GBPUSD 103 | GBPUSD_otc 104 | H33HKD 105 | IRRUSD_otc 106 | JODCNY_otc 107 | JPN225 108 | JPN225_otc 109 | LBPUSD_otc 110 | LINK_otc 111 | LNKUSD 112 | LTCUSD_otc 113 | MADUSD_otc 114 | MATIC_otc 115 | NASUSD 116 | NASUSD_otc 117 | NFLX 118 | NFLX_otc 119 | NZDJPY_otc 120 | NZDUSD_otc 121 | OMRCNY_otc 122 | QARCNY_otc 123 | SARCNY_otc 124 | SMI20 125 | SOL-USD_otc 126 | SP500 127 | SP500_otc 128 | SYPUSD_otc 129 | TNDUSD_otc 130 | TON-USD_otc 131 | TRX-USD_otc 132 | TWITTER 133 | TWITTER_otc 134 | UKBrent 135 | UKBrent_otc 136 | USCrude 137 | USCrude_otc 138 | USDARS_otc 139 | USDBDT_otc 140 | USDBRL_otc 141 | USDCAD 142 | USDCAD_otc 143 | USDCHF 144 | USDCHF_otc 145 | USDCLP_otc 146 | USDCNH_otc 147 | USDCOP_otc 148 | USDDZD_otc 149 | USDEGP_otc 150 | USDIDR_otc 151 | USDINR_otc 152 | USDJPY 153 | USDJPY_otc 154 | USDMXN_otc 155 | USDMYR_otc 156 | USDPHP_otc 157 | USDPKR_otc 158 | USDRUB_otc 159 | USDSGD_otc 160 | USDTHB_otc 161 | USDVND_otc 162 | VISA_otc 163 | XAGEUR 164 | XAGUSD 165 | XAGUSD_otc 166 | XAUEUR 167 | XAUUSD 168 | XAUUSD_otc 169 | XNGUSD 170 | XNGUSD_otc 171 | XPDUSD 172 | XPDUSD_otc 173 | XPTUSD 174 | XPTUSD_otc 175 | XRPUSD_otc 176 | YERUSD_otc 177 | -------------------------------------------------------------------------------- /tests/test-assets.py: -------------------------------------------------------------------------------- 1 | from BinaryOptionsToolsV2.pocketoption import PocketOptionAsync 2 | import asyncio 3 | import os 4 | 5 | # Function to read assets from a file 6 | def read_assets(filename): 7 | with open(filename, 'r') as f: 8 | assets = [line.strip() for line in f if line.strip()] 9 | return assets 10 | 11 | # Function to write assets to a file 12 | def write_asset(filename, asset): 13 | with open(filename, 'a') as f: 14 | f.write(asset + '\n') 15 | 16 | async def main(ssid: str): 17 | api = PocketOptionAsync(ssid) 18 | 19 | # Define file paths 20 | assets_file = 'tests/assets.txt' 21 | tested_assets_file = 'assets.tested.txt' 22 | not_working_assets_file = 'not-working-assets.txt' 23 | 24 | # Clear previous test results if files exist 25 | if os.path.exists(tested_assets_file): 26 | os.remove(tested_assets_file) 27 | if os.path.exists(not_working_assets_file): 28 | os.remove(not_working_assets_file) 29 | 30 | # Read assets from assets.txt 31 | assets_to_test = read_assets(assets_file) 32 | 33 | for asset in assets_to_test: 34 | print(f"Attempting to trade on asset: {asset}") 35 | try: 36 | # Attempt a buy trade with a small amount and short time 37 | # Setting check_win to False for initial trade attempt to quickly determine if it's a valid asset 38 | (trade_id, _) = await api.buy(asset=asset, amount=1.0, time=15, check_win=False) 39 | if trade_id: 40 | print(f"Trade successful for {asset}. Trade ID: {trade_id}") 41 | write_asset(tested_assets_file, asset) 42 | # Optionally, you might want to cancel the trade if you only want to test validity 43 | # await api.cancel_trade(trade_id) 44 | else: 45 | print(f"Trade failed for {asset}. No trade ID returned.") 46 | write_asset(not_working_assets_file, asset) 47 | except Exception as e: 48 | print(f"An error occurred while trading {asset}: {e}") 49 | write_asset(not_working_assets_file, asset) 50 | await asyncio.sleep(1) # Add a small delay to avoid overwhelming the API 51 | 52 | if __name__ == '__main__': 53 | ssid = input('Please enter your ssid: ') 54 | asyncio.run(main(ssid)) -------------------------------------------------------------------------------- /tutorials/How to get SSID.docx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ChipaDevTeam/BinaryOptionsTools-v2/739f401208a7160a076bb2349591bc0a081f1fb1/tutorials/How to get SSID.docx --------------------------------------------------------------------------------