walrasquant 0.3.2__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (110) hide show
  1. walrasquant-0.3.2/PKG-INFO +769 -0
  2. walrasquant-0.3.2/README.md +729 -0
  3. walrasquant-0.3.2/pyproject.toml +55 -0
  4. walrasquant-0.3.2/src/walrasquant/__init__.py +7 -0
  5. walrasquant-0.3.2/src/walrasquant/aggregation.py +440 -0
  6. walrasquant-0.3.2/src/walrasquant/backends/__init__.py +4 -0
  7. walrasquant-0.3.2/src/walrasquant/backends/db.py +131 -0
  8. walrasquant-0.3.2/src/walrasquant/backends/db_postgresql.py +356 -0
  9. walrasquant-0.3.2/src/walrasquant/backends/db_sqlite.py +346 -0
  10. walrasquant-0.3.2/src/walrasquant/base/__init__.py +26 -0
  11. walrasquant-0.3.2/src/walrasquant/base/api_client.py +56 -0
  12. walrasquant-0.3.2/src/walrasquant/base/connector.py +824 -0
  13. walrasquant-0.3.2/src/walrasquant/base/ems.py +660 -0
  14. walrasquant-0.3.2/src/walrasquant/base/exchange.py +209 -0
  15. walrasquant-0.3.2/src/walrasquant/base/oms.py +246 -0
  16. walrasquant-0.3.2/src/walrasquant/base/retry.py +220 -0
  17. walrasquant-0.3.2/src/walrasquant/base/sms.py +525 -0
  18. walrasquant-0.3.2/src/walrasquant/base/ws_client.py +406 -0
  19. walrasquant-0.3.2/src/walrasquant/cli/__init__.py +7 -0
  20. walrasquant-0.3.2/src/walrasquant/cli/app.py +191 -0
  21. walrasquant-0.3.2/src/walrasquant/cli/commands/__init__.py +1 -0
  22. walrasquant-0.3.2/src/walrasquant/cli/main.py +199 -0
  23. walrasquant-0.3.2/src/walrasquant/cli/monitor/__init__.py +1 -0
  24. walrasquant-0.3.2/src/walrasquant/cli/monitor/state_exporter.py +263 -0
  25. walrasquant-0.3.2/src/walrasquant/cli/widgets/__init__.py +1 -0
  26. walrasquant-0.3.2/src/walrasquant/cli/widgets/balances.py +104 -0
  27. walrasquant-0.3.2/src/walrasquant/cli/widgets/dashboard.py +106 -0
  28. walrasquant-0.3.2/src/walrasquant/cli/widgets/positions.py +111 -0
  29. walrasquant-0.3.2/src/walrasquant/config.py +229 -0
  30. walrasquant-0.3.2/src/walrasquant/constants.py +371 -0
  31. walrasquant-0.3.2/src/walrasquant/core/__init__.py +0 -0
  32. walrasquant-0.3.2/src/walrasquant/core/cache.py +701 -0
  33. walrasquant-0.3.2/src/walrasquant/core/connection.py +41 -0
  34. walrasquant-0.3.2/src/walrasquant/core/entity.py +482 -0
  35. walrasquant-0.3.2/src/walrasquant/core/nautilius_core.py +98 -0
  36. walrasquant-0.3.2/src/walrasquant/core/registry.py +39 -0
  37. walrasquant-0.3.2/src/walrasquant/engine.py +716 -0
  38. walrasquant-0.3.2/src/walrasquant/error.py +34 -0
  39. walrasquant-0.3.2/src/walrasquant/exchange/__init__.py +13 -0
  40. walrasquant-0.3.2/src/walrasquant/exchange/base_factory.py +170 -0
  41. walrasquant-0.3.2/src/walrasquant/exchange/binance/__init__.py +31 -0
  42. walrasquant-0.3.2/src/walrasquant/exchange/binance/connector.py +860 -0
  43. walrasquant-0.3.2/src/walrasquant/exchange/binance/constants.py +1186 -0
  44. walrasquant-0.3.2/src/walrasquant/exchange/binance/ems.py +136 -0
  45. walrasquant-0.3.2/src/walrasquant/exchange/binance/error.py +48 -0
  46. walrasquant-0.3.2/src/walrasquant/exchange/binance/exchange.py +123 -0
  47. walrasquant-0.3.2/src/walrasquant/exchange/binance/factory.py +106 -0
  48. walrasquant-0.3.2/src/walrasquant/exchange/binance/oms.py +1524 -0
  49. walrasquant-0.3.2/src/walrasquant/exchange/binance/rest_api.py +1484 -0
  50. walrasquant-0.3.2/src/walrasquant/exchange/binance/schema.py +978 -0
  51. walrasquant-0.3.2/src/walrasquant/exchange/binance/websockets.py +384 -0
  52. walrasquant-0.3.2/src/walrasquant/exchange/bitget/__init__.py +28 -0
  53. walrasquant-0.3.2/src/walrasquant/exchange/bitget/connector.py +575 -0
  54. walrasquant-0.3.2/src/walrasquant/exchange/bitget/constants.py +452 -0
  55. walrasquant-0.3.2/src/walrasquant/exchange/bitget/ems.py +215 -0
  56. walrasquant-0.3.2/src/walrasquant/exchange/bitget/error.py +36 -0
  57. walrasquant-0.3.2/src/walrasquant/exchange/bitget/exchange.py +111 -0
  58. walrasquant-0.3.2/src/walrasquant/exchange/bitget/factory.py +120 -0
  59. walrasquant-0.3.2/src/walrasquant/exchange/bitget/oms.py +1348 -0
  60. walrasquant-0.3.2/src/walrasquant/exchange/bitget/rest_api.py +614 -0
  61. walrasquant-0.3.2/src/walrasquant/exchange/bitget/schema.py +885 -0
  62. walrasquant-0.3.2/src/walrasquant/exchange/bitget/websockets.py +761 -0
  63. walrasquant-0.3.2/src/walrasquant/exchange/bybit/__init__.py +32 -0
  64. walrasquant-0.3.2/src/walrasquant/exchange/bybit/connector.py +796 -0
  65. walrasquant-0.3.2/src/walrasquant/exchange/bybit/constants.py +528 -0
  66. walrasquant-0.3.2/src/walrasquant/exchange/bybit/ems.py +114 -0
  67. walrasquant-0.3.2/src/walrasquant/exchange/bybit/error.py +36 -0
  68. walrasquant-0.3.2/src/walrasquant/exchange/bybit/exchange.py +102 -0
  69. walrasquant-0.3.2/src/walrasquant/exchange/bybit/factory.py +120 -0
  70. walrasquant-0.3.2/src/walrasquant/exchange/bybit/oms.py +978 -0
  71. walrasquant-0.3.2/src/walrasquant/exchange/bybit/rest_api.py +584 -0
  72. walrasquant-0.3.2/src/walrasquant/exchange/bybit/schema.py +848 -0
  73. walrasquant-0.3.2/src/walrasquant/exchange/bybit/websockets.py +306 -0
  74. walrasquant-0.3.2/src/walrasquant/exchange/hyperliquid/__init__.py +28 -0
  75. walrasquant-0.3.2/src/walrasquant/exchange/hyperliquid/connector.py +367 -0
  76. walrasquant-0.3.2/src/walrasquant/exchange/hyperliquid/constants.py +391 -0
  77. walrasquant-0.3.2/src/walrasquant/exchange/hyperliquid/ems.py +198 -0
  78. walrasquant-0.3.2/src/walrasquant/exchange/hyperliquid/error.py +48 -0
  79. walrasquant-0.3.2/src/walrasquant/exchange/hyperliquid/exchange.py +108 -0
  80. walrasquant-0.3.2/src/walrasquant/exchange/hyperliquid/factory.py +116 -0
  81. walrasquant-0.3.2/src/walrasquant/exchange/hyperliquid/oms.py +864 -0
  82. walrasquant-0.3.2/src/walrasquant/exchange/hyperliquid/rest_api.py +349 -0
  83. walrasquant-0.3.2/src/walrasquant/exchange/hyperliquid/schema.py +583 -0
  84. walrasquant-0.3.2/src/walrasquant/exchange/hyperliquid/websockets.py +576 -0
  85. walrasquant-0.3.2/src/walrasquant/exchange/okx/__init__.py +25 -0
  86. walrasquant-0.3.2/src/walrasquant/exchange/okx/connector.py +859 -0
  87. walrasquant-0.3.2/src/walrasquant/exchange/okx/constants.py +556 -0
  88. walrasquant-0.3.2/src/walrasquant/exchange/okx/ems.py +142 -0
  89. walrasquant-0.3.2/src/walrasquant/exchange/okx/error.py +63 -0
  90. walrasquant-0.3.2/src/walrasquant/exchange/okx/exchange.py +94 -0
  91. walrasquant-0.3.2/src/walrasquant/exchange/okx/factory.py +126 -0
  92. walrasquant-0.3.2/src/walrasquant/exchange/okx/oms.py +1027 -0
  93. walrasquant-0.3.2/src/walrasquant/exchange/okx/rest_api.py +843 -0
  94. walrasquant-0.3.2/src/walrasquant/exchange/okx/schema.py +1393 -0
  95. walrasquant-0.3.2/src/walrasquant/exchange/okx/websockets.py +420 -0
  96. walrasquant-0.3.2/src/walrasquant/exchange/registry.py +201 -0
  97. walrasquant-0.3.2/src/walrasquant/execution/__init__.py +24 -0
  98. walrasquant-0.3.2/src/walrasquant/execution/algorithm.py +924 -0
  99. walrasquant-0.3.2/src/walrasquant/execution/algorithms/__init__.py +3 -0
  100. walrasquant-0.3.2/src/walrasquant/execution/algorithms/twap.py +392 -0
  101. walrasquant-0.3.2/src/walrasquant/execution/config.py +34 -0
  102. walrasquant-0.3.2/src/walrasquant/execution/constants.py +27 -0
  103. walrasquant-0.3.2/src/walrasquant/execution/schema.py +62 -0
  104. walrasquant-0.3.2/src/walrasquant/indicator.py +374 -0
  105. walrasquant-0.3.2/src/walrasquant/push.py +74 -0
  106. walrasquant-0.3.2/src/walrasquant/schema.py +695 -0
  107. walrasquant-0.3.2/src/walrasquant/strategy.py +1582 -0
  108. walrasquant-0.3.2/src/walrasquant/web/__init__.py +16 -0
  109. walrasquant-0.3.2/src/walrasquant/web/app.py +157 -0
  110. walrasquant-0.3.2/src/walrasquant/web/server.py +89 -0
@@ -0,0 +1,769 @@
1
+ Metadata-Version: 2.3
2
+ Name: walrasquant
3
+ Version: 0.3.2
4
+ Summary: fastest python trading bot
5
+ Author: River-Shi
6
+ Author-email: River-Shi <nachuan.shi.quant@gmail.com>
7
+ License: MIT LICENSE
8
+ Requires-Dist: numpy>=1.26.4,<2.2.1
9
+ Requires-Dist: redis>=5.2.1,<6.0.0
10
+ Requires-Dist: msgspec>=0.19.0,<0.20.0
11
+ Requires-Dist: cython>=3.0.11,<4.0.0
12
+ Requires-Dist: certifi>=2025.1.31,<2026.0.0
13
+ Requires-Dist: bcrypt>=4.2.1,<5.0.0
14
+ Requires-Dist: zmq>=0.0.0,<0.0.1
15
+ Requires-Dist: apscheduler>=3.11.0,<4.0.0
16
+ Requires-Dist: returns>=0.24.0,<0.25.0
17
+ Requires-Dist: pathlib>=1.0.1,<2.0.0
18
+ Requires-Dist: aiosqlite>=0.21.0,<0.22.0
19
+ Requires-Dist: uvloop>=0.21.0
20
+ Requires-Dist: throttled-py>=2.2.3
21
+ Requires-Dist: asyncpg>=0.30.0
22
+ Requires-Dist: psycopg2-binary>=2.9.10
23
+ Requires-Dist: textual>=0.85.0
24
+ Requires-Dist: click>=8.1.0
25
+ Requires-Dist: pycryptodome>=3.23.0
26
+ Requires-Dist: eth-account>=0.13.7
27
+ Requires-Dist: typing-extensions>=4.12.2
28
+ Requires-Dist: fastapi>=0.117.1
29
+ Requires-Dist: uvicorn>=0.36.0
30
+ Requires-Dist: picows>=1.10.2
31
+ Requires-Dist: dynaconf[redis]>=3.2.12
32
+ Requires-Dist: nexuslog>=0.4.4
33
+ Requires-Dist: pandas>=2.3.3,<3.0.0
34
+ Requires-Dist: walras-nexuscore>=0.1.3
35
+ Requires-Dist: flashduty-sdk>=0.1.1
36
+ Requires-Dist: httpx>=0.28.1
37
+ Requires-Dist: ccxt>=4.5.34
38
+ Requires-Python: >=3.11, <3.14
39
+ Description-Content-Type: text/markdown
40
+
41
+ <picture>
42
+ <source media="(prefers-color-scheme: dark)" srcset="docs/source/_static/logo-dark.png">
43
+ <source media="(prefers-color-scheme: light)" srcset="docs/source/_static/logo-light.png">
44
+ <img alt="nexustrader Logo" src="docs/source/_static/logo-light.png">
45
+ </picture>
46
+
47
+
48
+ ---
49
+
50
+ ![License](https://img.shields.io/badge/license-MIT-blue.svg)![Python](https://img.shields.io/badge/python-3.11%20|%203.12%20|%203.13-blue)![Version](https://img.shields.io/pypi/v/nexustrader?&color=blue)
51
+
52
+ - **WebSite**: https://nexustrader.quantweb3.ai/
53
+ - **Docs**: https://nexustrader.readthedocs.io/en/latest/
54
+ - **Support**: [quantweb3.ai@gmail.com](mailto:quantweb3.ai@gmail.com)
55
+
56
+ ```python
57
+ ###############################################################
58
+ ## ##
59
+ ## ##
60
+ ## ███  ██ ███████ ██  ██ ██  ██ ███████  ##
61
+ ## ████  ██ ██       ██ ██  ██  ██ ██       ##
62
+ ## ██ ██  ██ █████   ███   ██  ██ ███████  ##
63
+ ## ██  ██ ██ ██     ██ ██  ██  ██      ██  ##
64
+ ## ██   ████ ███████ ██   ██  ██████  ███████  ##
65
+ ## ##
66
+ ## ##
67
+ ## ████████ ██████  █████  ██████ ███████ ██████ ##
68
+ ##    ██    ██   ██ ██   ██ ██   ██ ██      ██   ██ ##
69
+ ## ██  ██████  ███████ ██  ██ █████  ██████ ##
70
+ ## ██  ██   ██ ██   ██ ██  ██ ██     ██   ██ ##
71
+ ## ██  ██  ██ ██  ██ ██████ ███████ ██  ██ ##
72
+ ## ##
73
+ ## ##
74
+ ###############################################################
75
+ ```
76
+ ## Introduction
77
+
78
+ NexusTrader is a professional-grade open-source quantitative trading platform, specifically designed for **large capital
79
+ management** and **complex strategy development**, dedicated to providing high-performance, scalable, and user-friendly
80
+ quantitative trading solutions.
81
+
82
+ ## Overview
83
+
84
+ ### Core Advantages
85
+
86
+ - 🚀 **Professionally Optimized Order Algorithms:** Deep optimization for algorithmic orders including TWAP, effectively
87
+ reducing market impact costs. Users can easily integrate their own execution signals to achieve more efficient and
88
+ precise order execution.
89
+ - 💰 **Professional Arbitrage Strategy Support:** Provides professional optimization for various arbitrage strategies,
90
+ including funding rate arbitrage and cross-exchange arbitrage, supporting real-time tracking and trading of thousands
91
+ of trading pairs to help users easily capture arbitrage opportunities.
92
+ - 🚧 **Full-Featured Quantitative Trading Framework:** Users don't need to build frameworks or handle complex exchange
93
+ interface details themselves. NexusTrader has integrated professional position management, order management, fund
94
+ management, and statistical analysis modules, allowing users to focus on writing strategy logic and quickly implement
95
+ quantitative trading.
96
+ - 🚀 **Multi-Market Support and High Scalability:** Supports large-scale multi-market tracking and high-frequency strategy
97
+ execution, covering a wide range of trading instruments, making it an ideal choice for professional trading needs.
98
+
99
+ ### Why NexusTrader Is More Efficient?
100
+
101
+ - **Enhanced Event Loop Performance**: NexusTrader leverages [uvloop](https://github.com/MagicStack/uvloop), a high-performance event loop, delivering speeds up to 2-4 times faster than Python's default asyncio loop.
102
+
103
+ - **High-Performance WebSocket Framework**: Built with [picows](https://github.com/tarasko/picows), a Cython-based WebSocket library that matches the speed of C++'s Boost.Beast, significantly outperforming Python alternatives like websockets and aiohttp.
104
+
105
+ - **Optimized Data Serialization**: Utilizing `msgspec` for serialization and deserialization, NexusTrader achieves unmatched efficiency, surpassing tools like `orjson`, `ujson`, and `json`. All data classes are implemented with `msgspec.Struct` for maximum performance.
106
+
107
+ - **Scalable Order Management**: Orders are handled efficiently using `asyncio.Queue`, ensuring seamless processing even at high volumes.
108
+
109
+ - **Rust-Powered Core Components**: Core modules such as the MessageBus and Clock are implemented in Rust, combining Rust's speed and reliability with Python's flexibility through the [nautilius](https://github.com/nautilius/nautilius) framework.
110
+
111
+ ### Comparison with Other Frameworks
112
+
113
+ | Framework | Websocket Package | Data Serialization | Strategy Support | Advantages | Disadvantages |
114
+ | ------------------------------------------------------------ | ------------------------------------------------------------ | -------------------------------------------------- | ---------------- | -------------------------------------------------- | ------------------------------------------------- |
115
+ | **NexusTrader** | [picows](https://picows.readthedocs.io/en/stable/introduction.html#installation) | [msgspec](https://jcristharif.com/msgspec/) | ✅ | Professionally optimized for speed and low latency | Requires some familiarity with async workflows |
116
+ | [HummingBot](https://github.com/hummingbot/hummingbot?tab=readme-ov-file) | aiohttp | [ujson](https://pypi.org/project/ujson/) | ✅ | Widely adopted with robust community support | Slower WebSocket handling and limited flexibility |
117
+ | [Freqtrade](https://github.com/freqtrade/freqtrade) | websockets | [orjson](https://github.com/ijl/orjson) | ✅ | Flexible strategy support | Higher resource consumption |
118
+ | [crypto-feed](https://github.com/bmoscon/cryptofeed) | [websockets](https://websockets.readthedocs.io/en/stable/) | [yapic.json](https://pypi.org/project/yapic.json/) | ❌ | Simple design for feed-only use | Lacks trading support and advanced features |
119
+ | [ccxt](https://github.com/bmoscon/cryptofeed) | [aiohttp](https://docs.aiohttp.org/en/stable/client_reference.html) | json | ❌ | Great REST API support | Limited WebSocket performance |
120
+ | [binance-futures-connector](https://github.com/binance/binance-futures-connector-python) | [websocket-client](https://websocket-client.readthedocs.io/en/latest/examples.html) | json | ❌ | Optimized for Binance-specific integration | Limited to Binance Futures |
121
+ | [python-okx](https://github.com/okxapi/python-okx) | websockets | json | ❌ | Dedicated to OKX trading | Limited to OKX platform |
122
+ | [unicorn-binance-websocket-api](https://github.com/LUCIT-Systems-and-Development/unicorn-binance-websocket-api) | websockets | [ujson](https://pypi.org/project/ujson/) | ❌ | Easy-to-use for Binance users | Restricted to Binance and resource-heavy |
123
+
124
+ ### Architecture (data flow)
125
+ The core of Tradebot is the `Connector`, which is responsible for connecting to the exchange and data flow. Through the `PublicConnector`, users can access market data from the exchange, and through the `PrivateConnector`, users can execute trades and receive callbacks for trade data. Orders are submitted through the ``OrderExecutionSystem``, which is responsible for submitting orders to the exchange and obtaining the order ID from the exchange. Order status management is handled by the `OrderManagementSystem`, which is responsible for managing the status of orders and sending them to the `Strategy`.
126
+
127
+ ![Architecture](docs/source/_static/arch.png "architecture")
128
+
129
+ ### Features
130
+
131
+ - 🌍 Multi-Exchange Integration: Effortlessly connect to top exchanges like Binance, Bybit, and OKX, with an extensible design to support additional platforms.
132
+ - ⚡ Asynchronous Operations: Built on asyncio for highly efficient, scalable performance, even during high-frequency trading.
133
+ - 📡 Real-Time Data Streaming: Reliable WebSocket support for live market data, order book updates, and trade execution notifications.
134
+ - 📊 Advanced Order Management: Execute diverse order types (limit, market, stop) with optimized, professional-grade order handling.
135
+ - 📋 Account Monitoring: Real-time tracking of balances, positions, and PnL across multiple exchanges with integrated monitoring tools.
136
+ - 🛠️ Modular Architecture: Flexible framework to add exchanges, instruments, or custom strategies with ease.
137
+ - 🔄 Strategy Execution & Backtesting: Seamlessly transition from strategy testing to live trading with built-in tools.
138
+ - 📈 Scalability: Designed to handle large-scale, multi-market operations for retail and institutional traders alike.
139
+ - 💰 Risk & Fund Management: Optimize capital allocation and control risk exposure with integrated management tools.
140
+ - 🔔 Instant Notifications: Stay updated with alerts for trades, market changes, and custom conditions.
141
+
142
+ ### Supported Exchanges
143
+
144
+ | OKX | Binance | BYBIT | HYPERLIQUID | BITGET |
145
+ | --------| ------ | ------- | ------- | ------- |
146
+ | <img src="https://images-wixmp-ed30a86b8c4ca887773594c2.wixmp.com/f/9a411426-3711-47d4-9c1a-dcf72973ddfc/dfj37e6-d8b49926-d115-4368-9de8-09a80077fb4f.png/v1/fill/w_1280,h_1280/okx_okb_logo_by_saphyl_dfj37e6-fullview.png?token=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJ1cm46YXBwOjdlMGQxODg5ODIyNjQzNzNhNWYwZDQxNWVhMGQyNmUwIiwiaXNzIjoidXJuOmFwcDo3ZTBkMTg4OTgyMjY0MzczYTVmMGQ0MTVlYTBkMjZlMCIsIm9iaiI6W1t7ImhlaWdodCI6Ijw9MTI4MCIsInBhdGgiOiJcL2ZcLzlhNDExNDI2LTM3MTEtNDdkNC05YzFhLWRjZjcyOTczZGRmY1wvZGZqMzdlNi1kOGI0OTkyNi1kMTE1LTQzNjgtOWRlOC0wOWE4MDA3N2ZiNGYucG5nIiwid2lkdGgiOiI8PTEyODAifV1dLCJhdWQiOlsidXJuOnNlcnZpY2U6aW1hZ2Uub3BlcmF0aW9ucyJdfQ.kH6v6nu55xLephOzAFFhD2uCYkmFdLsBoTkSuQvtBpo" width="100"> | <img src="https://upload.wikimedia.org/wikipedia/commons/thumb/e/e8/Binance_Logo.svg/768px-Binance_Logo.svg.png" width="100"> | <img src="https://brandlogo.org/wp-content/uploads/2024/02/Bybit-Logo.png" width="100"> | <img src="https://avatars.githubusercontent.com/u/129421375?s=280&v=4" width="100"> | <img src="https://s2.coinmarketcap.com/static/img/coins/200x200/11092.png" width="100"> |
147
+
148
+ ## Installation
149
+
150
+ ### Prerequisites
151
+
152
+ - Python 3.11+
153
+ - Redis
154
+ - Poetry (recommended)
155
+ - build-essential
156
+
157
+ ### Install Build Essentials
158
+
159
+ ```bash
160
+ sudo apt-get update
161
+ sudo apt-get install build-essential
162
+ ```
163
+
164
+ ### From PyPI
165
+
166
+ ```bash
167
+ pip install nexustrader
168
+ ```
169
+
170
+ ### From Source
171
+
172
+ ```bash
173
+ git clone https://github.com/RiverTrading/NexusTrader
174
+ cd NexusTrader
175
+ poetry install
176
+ ```
177
+
178
+ > **Note**
179
+ > more details can be found in the [installation guide](https://nexustrader.readthedocs.io/en/latest/installation.html)
180
+
181
+ ### Quick Start
182
+
183
+ Here's a basic example of how to use nexustrader, demonstrating a simple buy and sell strategy on OKX.
184
+
185
+ ```python
186
+ from decimal import Decimal
187
+
188
+ from nexustrader.constants import settings
189
+ from nexustrader.config import Config, PublicConnectorConfig, PrivateConnectorConfig, BasicConfig
190
+ from nexustrader.strategy import Strategy
191
+ from nexustrader.constants import ExchangeType, OrderSide, OrderType
192
+ from nexustrader.exchange.okx import OkxAccountType
193
+ from nexustrader.schema import BookL1, Order
194
+ from nexustrader.engine import Engine
195
+
196
+ # Retrieve API credentials from settings
197
+ OKX_API_KEY = settings.OKX.DEMO_1.api_key
198
+ OKX_SECRET = settings.OKX.DEMO_1.secret
199
+ OKX_PASSPHRASE = settings.OKX.DEMO_1.passphrase
200
+
201
+
202
+ class Demo(Strategy):
203
+ def __init__(self):
204
+ super().__init__()
205
+ self.subscribe_bookl1(symbols=["BTCUSDT-PERP.OKX"]) # Subscribe to the order book for the specified symbol
206
+ self.signal = True # Initialize signal to control order execution
207
+
208
+ def on_failed_order(self, order: Order):
209
+ print(order) # Log failed orders
210
+
211
+ def on_pending_order(self, order: Order):
212
+ print(order) # Log pending orders
213
+
214
+ def on_accepted_order(self, order: Order):
215
+ print(order) # Log accepted orders
216
+
217
+ def on_partially_filled_order(self, order: Order):
218
+ print(order) # Log partially filled orders
219
+
220
+ def on_filled_order(self, order: Order):
221
+ print(order) # Log filled orders
222
+
223
+ def on_bookl1(self, bookl1: BookL1):
224
+ if self.signal: # Check if the signal is active
225
+ # Create a market buy order
226
+ self.create_order(
227
+ symbol="BTCUSDT-PERP.OKX",
228
+ side=OrderSide.BUY,
229
+ type=OrderType.MARKET,
230
+ amount=Decimal("0.1"),
231
+ )
232
+ # Create a market sell order
233
+ self.create_order(
234
+ symbol="BTCUSDT-PERP.OKX",
235
+ side=OrderSide.SELL,
236
+ type=OrderType.MARKET,
237
+ amount=Decimal("0.1"),
238
+ )
239
+ self.signal = False # Deactivate the signal after placing orders
240
+
241
+
242
+ # Configuration for the trading strategy
243
+ config = Config(
244
+ strategy_id="okx_buy_and_sell",
245
+ user_id="user_test",
246
+ strategy=Demo(),
247
+ basic_config={
248
+ ExchangeType.OKX: BasicConfig(
249
+ api_key=OKX_API_KEY,
250
+ secret=OKX_SECRET,
251
+ passphrase=OKX_PASSPHRASE,
252
+ testnet=True, # Use testnet for safe trading
253
+ )
254
+ },
255
+ public_conn_config={
256
+ ExchangeType.OKX: [
257
+ PublicConnectorConfig(
258
+ account_type=OkxAccountType.DEMO, # Specify demo account type
259
+ )
260
+ ]
261
+ },
262
+ private_conn_config={
263
+ ExchangeType.OKX: [
264
+ PrivateConnectorConfig(
265
+ account_type=OkxAccountType.DEMO, # Specify demo account type
266
+ )
267
+ ]
268
+ }
269
+ )
270
+
271
+ # Initialize the trading engine with the configuration
272
+ engine = Engine(config)
273
+
274
+ if __name__ == "__main__":
275
+ try:
276
+ engine.start() # Start the trading engine
277
+ finally:
278
+ engine.dispose() # Ensure resources are cleaned up
279
+
280
+ ```
281
+
282
+ ### Web Callbacks
283
+
284
+ NexusTrader can host FastAPI endpoints alongside a running strategy. Define an application with
285
+ `nexustrader.web.create_strategy_app`, decorate a method that accepts `self`, and enable the web server in your config.
286
+
287
+ ```python
288
+ from fastapi import Body
289
+
290
+ from nexustrader.web import create_strategy_app
291
+ from nexustrader.config import WebConfig
292
+
293
+
294
+ class Demo(Strategy):
295
+ web_app = create_strategy_app(title="Demo strategy API")
296
+
297
+ @web_app.post("/toggle")
298
+ async def on_web_cb(self, payload: dict = Body(...)):
299
+ self.signal = payload.get("signal", True)
300
+ return {"signal": self.signal}
301
+
302
+
303
+ config = Config(
304
+ strategy_id="demo",
305
+ user_id="user",
306
+ strategy=Demo(),
307
+ basic_config={...},
308
+ public_conn_config={...},
309
+ private_conn_config={...},
310
+ web_config=WebConfig(enabled=True, host="127.0.0.1", port=9000),
311
+ )
312
+ ```
313
+
314
+ When the engine starts, it binds the strategy instance to the FastAPI routes and serves them in the background using
315
+ Uvicorn. Routes automatically disappear once the engine stops.
316
+
317
+ This example illustrates how easy it is to switch between different exchanges and strategies by modifying the `config`
318
+ class. For instance, to switch to Binance, you can adjust the configuration as follows, and change the symbol to
319
+ `BTCUSDT-PERP.BINANCE`.
320
+
321
+ ```python
322
+ from nexustrader.exchange.binance import BinanceAccountType
323
+
324
+ config = Config(
325
+ strategy_id="buy_and_sell_binance",
326
+ user_id="user_test",
327
+ strategy=Demo(),
328
+ basic_config={
329
+ ExchangeType.BINANCE: BasicConfig(
330
+ api_key=BINANCE_API_KEY,
331
+ secret=BINANCE_SECRET,
332
+ testnet=True, # Use testnet for safe trading
333
+ )
334
+ },
335
+ public_conn_config={
336
+ ExchangeType.BINANCE: [
337
+ PublicConnectorConfig(
338
+ account_type=BinanceAccountType.USD_M_FUTURE_TESTNET, # Specify account type for Binance
339
+ )
340
+ ]
341
+ },
342
+ private_conn_config={
343
+ ExchangeType.BINANCE: [
344
+ PrivateConnectorConfig(
345
+ account_type=BinanceAccountType.USD_M_FUTURE_TESTNET, # Specify account type for Binance
346
+ )
347
+ ]
348
+ }
349
+ )
350
+ ```
351
+
352
+ ## Multi-Mode Support
353
+
354
+ nexustrader supports multiple modes of operation to cater to different trading strategies and requirements. Each mode
355
+ allows for flexibility in how trading logic is executed based on market conditions or specific triggers.
356
+
357
+ ### Event-Driven Mode
358
+
359
+ In this mode, trading logic is executed in response to real-time market events. The methods `on_bookl1`, `on_trade`, and
360
+ `on_kline` are triggered whenever relevant data is updated, allowing for immediate reaction to market changes.
361
+
362
+ ```python
363
+ class Demo(Strategy):
364
+ def __init__(self):
365
+ super().__init__()
366
+ self.subscribe_bookl1(symbols=["BTCUSDT-PERP.BINANCE"])
367
+
368
+ def on_bookl1(self, bookl1: BookL1):
369
+ # implement the trading logic Here
370
+ pass
371
+ ```
372
+
373
+ ### Timer Mode
374
+
375
+ This mode allows you to schedule trading logic to run at specific intervals. You can use the `schedule` method to define
376
+ when your trading algorithm should execute, making it suitable for strategies that require periodic checks or actions.
377
+
378
+ ```python
379
+ class Demo2(Strategy):
380
+ def __init__(self):
381
+ super().__init__()
382
+ self.schedule(self.algo, trigger="interval", seconds=1)
383
+
384
+ def algo(self):
385
+ # run every 1 second
386
+ # implement the trading logic Here
387
+ pass
388
+ ```
389
+
390
+ ### Custom Signal Mode
391
+
392
+ In this mode, trading logic is executed based on custom signals. You can define your own signals and use the
393
+ `on_custom_signal` method to trigger trading actions when these signals are received. This is particularly useful for
394
+ integrating with external systems or custom event sources.
395
+
396
+ ```python
397
+ class Demo3(Strategy):
398
+ def __init__(self):
399
+ super().__init__()
400
+ self.signal = True
401
+
402
+ def on_custom_signal(self, signal: object):
403
+ # implement the trading logic Here,
404
+ # signal can be any object, it is up to you to define the signal
405
+ pass
406
+ ```
407
+
408
+ ## Define Your Own Indicator
409
+
410
+ NexusTrader provides a powerful framework for creating custom indicators with built-in warmup functionality. This allows your indicators to automatically fetch historical data and prepare themselves before live trading begins.
411
+
412
+ Here's an example of creating a custom Moving Average indicator with automatic warmup:
413
+
414
+ ```python
415
+ from collections import deque
416
+ from nexustrader.indicator import Indicator
417
+ from nexustrader.constants import KlineInterval, DataType
418
+ from nexustrader.schema import Kline, BookL1, BookL2, Trade
419
+ from nexustrader.strategy import Strategy
420
+ from nexustrader.exchange.bybit import BybitAccountType
421
+
422
+ class MovingAverageIndicator(Indicator):
423
+ def __init__(self, period: int = 20):
424
+ super().__init__(
425
+ params={"period": period},
426
+ name=f"MA_{period}",
427
+ warmup_period=period * 2, # Define warmup period
428
+ warmup_interval=KlineInterval.MINUTE_1, # Define warmup interval
429
+ )
430
+ self.period = period
431
+ self.prices = deque(maxlen=period)
432
+ self.current_ma = None
433
+
434
+ def handle_kline(self, kline: Kline):
435
+ if not kline.confirm: # Only process confirmed klines
436
+ return
437
+
438
+ self.prices.append(kline.close)
439
+
440
+ # Calculate moving average if we have enough data
441
+ if len(self.prices) >= self.period:
442
+ self.current_ma = sum(self.prices) / len(self.prices)
443
+
444
+ def handle_bookl1(self, bookl1: BookL1):
445
+ pass # Implement if needed
446
+
447
+ def handle_bookl2(self, bookl2: BookL2):
448
+ pass # Implement if needed
449
+
450
+ def handle_trade(self, trade: Trade):
451
+ pass # Implement if needed
452
+
453
+ @property
454
+ def value(self):
455
+ return self.current_ma
456
+
457
+ class MyStrategy(Strategy):
458
+ def __init__(self):
459
+ super().__init__()
460
+ self.symbol = "UNIUSDT-PERP.BYBIT"
461
+ self.ma_20 = MovingAverageIndicator(period=20)
462
+ self.ma_50 = MovingAverageIndicator(period=50)
463
+
464
+ def on_start(self):
465
+ # Subscribe to kline data
466
+ self.subscribe_kline(
467
+ symbols=self.symbol,
468
+ interval=KlineInterval.MINUTE_1,
469
+ )
470
+
471
+ # Register indicators with automatic warmup
472
+ self.register_indicator(
473
+ symbols=self.symbol,
474
+ indicator=self.ma_20,
475
+ data_type=DataType.KLINE,
476
+ account_type=BybitAccountType.LINEAR,
477
+ )
478
+
479
+ self.register_indicator(
480
+ symbols=self.symbol,
481
+ indicator=self.ma_50,
482
+ data_type=DataType.KLINE,
483
+ account_type=BybitAccountType.LINEAR,
484
+ )
485
+
486
+ def on_kline(self, kline: Kline):
487
+ # Wait for indicators to warm up
488
+ if not self.ma_20.is_warmed_up or not self.ma_50.is_warmed_up:
489
+ self.log.info("Indicators still warming up...")
490
+ return
491
+
492
+ if not kline.confirm:
493
+ return
494
+
495
+ if self.ma_20.value and self.ma_50.value:
496
+ self.log.info(
497
+ f"MA20: {self.ma_20.value:.4f}, MA50: {self.ma_50.value:.4f}, "
498
+ f"Current Price: {kline.close:.4f}"
499
+ )
500
+
501
+ # Simple golden cross strategy
502
+ if self.ma_20.value > self.ma_50.value:
503
+ self.log.info("Golden Cross - Bullish signal!")
504
+ elif self.ma_20.value < self.ma_50.value:
505
+ self.log.info("Death Cross - Bearish signal!")
506
+ ```
507
+
508
+ #### Key Features of Custom Indicators:
509
+
510
+ 1. **Automatic Warmup**: Set `warmup_period` and `warmup_interval` to automatically fetch historical data
511
+ 2. **Data Handlers**: Implement `handle_kline`, `handle_bookl1`, `handle_bookl2`, and `handle_trade` as needed
512
+ 3. **Value Property**: Expose your indicator's current value through the `value` property
513
+ 4. **Warmup Status**: Check `is_warmed_up` property to ensure indicator is ready before using
514
+ 5. **Flexible Parameters**: Pass custom parameters through the `params` dictionary
515
+
516
+ This approach ensures your indicators have sufficient historical data before making trading decisions, improving the reliability and accuracy of your trading strategies.
517
+
518
+ ## Execution Algorithms
519
+
520
+ NexusTrader provides a powerful execution algorithm framework for implementing advanced order execution strategies like TWAP, VWAP, iceberg orders, and more. This allows you to split large orders into smaller chunks and execute them over time to minimize market impact.
521
+
522
+ ### Using TWAP (Time-Weighted Average Price)
523
+
524
+ The built-in `TWAPExecAlgorithm` splits a large order into smaller slices and executes them at regular intervals over a specified time horizon.
525
+
526
+ ```python
527
+ from decimal import Decimal
528
+ from datetime import timedelta
529
+ from nexustrader.constants import OrderSide
530
+ from nexustrader.strategy import Strategy
531
+ from nexustrader.engine import Engine
532
+ from nexustrader.execution import TWAPExecAlgorithm
533
+
534
+ class MyStrategy(Strategy):
535
+ def __init__(self):
536
+ super().__init__()
537
+ self.symbol = "BTCUSDT-PERP.BINANCE"
538
+
539
+ def on_start(self):
540
+ self.subscribe_bookl1(self.symbol)
541
+ # Schedule TWAP order placement
542
+ self.schedule(
543
+ func=self.place_twap_order,
544
+ trigger="date",
545
+ run_date=self.clock.utc_now() + timedelta(seconds=10),
546
+ )
547
+
548
+ def place_twap_order(self):
549
+ # Execute 1 BTC over 5 minutes with 30-second intervals (10 slices)
550
+ self.create_algo_order(
551
+ symbol=self.symbol,
552
+ side=OrderSide.BUY,
553
+ amount=Decimal("1.0"),
554
+ exec_algorithm_id="TWAP",
555
+ exec_params={
556
+ "horizon_secs": 300, # Total execution time: 5 minutes
557
+ "interval_secs": 30, # Interval between slices: 30 seconds
558
+ },
559
+ )
560
+
561
+ # Register the execution algorithm with the engine
562
+ engine = Engine(config)
563
+ engine.add_exec_algorithm(algorithm=TWAPExecAlgorithm())
564
+ ```
565
+
566
+ #### TWAP Parameters
567
+
568
+ | Parameter | Type | Required | Description |
569
+ |-----------|------|----------|-------------|
570
+ | `horizon_secs` | int | Yes | Total execution time horizon in seconds |
571
+ | `interval_secs` | int | Yes | Interval between order slices in seconds |
572
+ | `use_limit` | bool | No | If True, use limit orders instead of market orders (default: False) |
573
+ | `n_tick_sz` | int | No | Number of tick sizes to offset from best bid/ask for limit orders. Positive = more passive, Negative = more aggressive (default: 0) |
574
+
575
+ #### TWAP with Limit Orders
576
+
577
+ For better price execution, you can use limit orders with price offsets:
578
+
579
+ ```python
580
+ self.create_algo_order(
581
+ symbol="BTCUSDT-PERP.OKX",
582
+ side=OrderSide.BUY,
583
+ amount=Decimal("2.0"),
584
+ exec_algorithm_id="TWAP",
585
+ exec_params={
586
+ "horizon_secs": 100,
587
+ "interval_secs": 10,
588
+ "use_limit": True, # Use limit orders
589
+ "n_tick_sz": 1, # Place 1 tick below best ask (for buy)
590
+ },
591
+ reduce_only=True, # Optional: only reduce existing position
592
+ )
593
+ ```
594
+
595
+ ### Creating Custom Execution Algorithms
596
+
597
+ You can create your own execution algorithms by subclassing `ExecAlgorithm`. The key method to implement is `on_order()`, which is called when a new algorithmic order is received.
598
+
599
+ ```python
600
+ from decimal import Decimal
601
+ from nexustrader.execution.algorithm import ExecAlgorithm
602
+ from nexustrader.execution.config import ExecAlgorithmConfig
603
+ from nexustrader.execution.schema import ExecAlgorithmOrder
604
+ from nexustrader.execution.constants import ExecAlgorithmStatus
605
+ from nexustrader.schema import Order
606
+
607
+
608
+ class MyAlgoConfig(ExecAlgorithmConfig, kw_only=True, frozen=True):
609
+ """Configuration for custom algorithm."""
610
+ exec_algorithm_id: str = "MY_ALGO"
611
+
612
+
613
+ class MyExecAlgorithm(ExecAlgorithm):
614
+ """Custom execution algorithm example."""
615
+
616
+ def __init__(self, config: MyAlgoConfig | None = None):
617
+ if config is None:
618
+ config = MyAlgoConfig()
619
+ super().__init__(config)
620
+
621
+ def on_order(self, exec_order: ExecAlgorithmOrder):
622
+ """
623
+ Main entry point - called when create_algo_order() is invoked.
624
+
625
+ Parameters
626
+ ----------
627
+ exec_order : ExecAlgorithmOrder
628
+ Contains: primary_oid, symbol, side, total_amount, remaining_amount, params
629
+ """
630
+ # Access custom parameters
631
+ params = exec_order.params
632
+ my_param = params.get("my_param", "default")
633
+
634
+ # Spawn child orders using available methods:
635
+ # - spawn_market(exec_order, quantity)
636
+ # - spawn_limit(exec_order, quantity, price)
637
+ # - spawn_market_ws / spawn_limit_ws for WebSocket submission
638
+
639
+ # Example: split into two market orders
640
+ half = self.amount_to_precision(
641
+ exec_order.symbol,
642
+ exec_order.total_amount / 2,
643
+ mode="floor"
644
+ )
645
+ self.spawn_market(exec_order, half)
646
+ self.spawn_market(exec_order, exec_order.total_amount - half)
647
+
648
+ def on_spawned_order_filled(self, exec_order: ExecAlgorithmOrder, order: Order):
649
+ """Called when a spawned order is filled."""
650
+ if exec_order.remaining_amount <= 0:
651
+ self.mark_complete(exec_order)
652
+
653
+ def on_cancel(self, exec_order: ExecAlgorithmOrder):
654
+ """Handle cancellation request."""
655
+ exec_order.status = ExecAlgorithmStatus.CANCELED
656
+ ```
657
+
658
+ #### Key Methods to Override
659
+
660
+ | Method | Description |
661
+ |--------|-------------|
662
+ | `on_order(exec_order)` | **Required.** Main entry point when a new order is received |
663
+ | `on_start()` | Called when the algorithm starts |
664
+ | `on_stop()` | Called when the algorithm stops |
665
+ | `on_cancel(exec_order)` | Called when cancellation is requested |
666
+ | `on_execution_complete(exec_order)` | Called when execution completes |
667
+ | `on_spawned_order_filled(exec_order, order)` | Called when a spawned order is filled |
668
+ | `on_spawned_order_failed(exec_order, order)` | Called when a spawned order fails |
669
+
670
+ #### Utility Methods
671
+
672
+ | Method | Description |
673
+ |--------|-------------|
674
+ | `spawn_market(exec_order, quantity)` | Spawn a market order |
675
+ | `spawn_limit(exec_order, quantity, price)` | Spawn a limit order |
676
+ | `cancel_spawned_order(exec_order, spawned_oid)` | Cancel a spawned order |
677
+ | `mark_complete(exec_order)` | Mark execution as complete |
678
+ | `set_timer(name, interval, callback)` | Set a timer for scheduled execution |
679
+ | `amount_to_precision(symbol, amount)` | Convert amount to market precision |
680
+ | `price_to_precision(symbol, price)` | Convert price to market precision |
681
+ | `min_order_amount(symbol)` | Get minimum order amount |
682
+ | `cache.bookl1(symbol)` | Get current L1 order book |
683
+
684
+ #### Register and Use
685
+
686
+ ```python
687
+ engine = Engine(config)
688
+ engine.add_exec_algorithm(algorithm=MyExecAlgorithm())
689
+
690
+ # In strategy:
691
+ self.create_algo_order(
692
+ symbol="BTCUSDT-PERP.BINANCE",
693
+ side=OrderSide.BUY,
694
+ amount=Decimal("1.0"),
695
+ exec_algorithm_id="MY_ALGO",
696
+ exec_params={"my_param": "value"},
697
+ )
698
+ ```
699
+
700
+ ## Contributing
701
+
702
+ Thank you for considering contributing to nexustrader! We greatly appreciate any effort to help improve the project. If
703
+ you have an idea for an enhancement or a bug fix, the first step is to open
704
+ an [issue](https://github.com/Quantweb3-ai/tradebot-pro/issues) on GitHub. This allows us to discuss your proposal and
705
+ ensure it aligns with the project's goals, while also helping to avoid duplicate efforts.
706
+
707
+ When you're ready to start working on your contribution, please review the guidelines in
708
+ the [CONTRIBUTING.md](./CONTRIBUTING.md) file. Depending on the nature of your contribution, you may also need to sign a
709
+ Contributor License Agreement (CLA) to ensure it can be included in the project.
710
+
711
+ > **Note**
712
+ > Pull requests should be directed to the `main` branch (the default branch), where new features and improvements are
713
+ > integrated before release.
714
+
715
+ Thank you again for your interest in nexustrader! We look forward to reviewing your contributions and collaborating with
716
+ you to make the project even better.
717
+
718
+ ## VIP Privileges
719
+
720
+ Trading on our platform is free. Become a VIP customer to enjoy exclusive technical support privileges for $499 per month ([Subscription Here](https://quantweb3.ai/subscribe/ ))—or get VIP status at no cost by opening an account through our partnership links.
721
+
722
+ Our partners include global leading trading platforms like Bybit, OKX, ZFX, Bison and others. By opening an account through our referral links, you'll enjoy these benefits:
723
+
724
+ Instant Account Benefits
725
+
726
+ 1. Trading Fee Discounts: Exclusive discounts to lower your trading costs.
727
+ 2. VIP Service Support: Contact us after opening your account to become our VIP customer. Enjoy exclusive events and benefits for the ultimate VIP experience.
728
+
729
+ Act now and join our VIP program!
730
+
731
+ > Click the links below to register
732
+
733
+ - [Bybit](https://partner.bybit.com/b/90899)
734
+ - [OKX](http://www.okx.com/join/80353297)
735
+ - [ZFX](https://zfx.link/46dFByp)
736
+ - [Bison](https://m.bison.com/#/register?invitationCode=1002)
737
+
738
+ ## Social
739
+
740
+ Connect with us on your favorite platforms:
741
+
742
+ [![X (Twitter)](https://img.shields.io/badge/X_(Twitter)-000000?logo=x&logoColor=white)](https://x.com/quantweb3_ai) Stay updated with our latest news, features, and announcements.
743
+
744
+ [![Discord](https://img.shields.io/badge/Discord-5865F2?logo=discord&logoColor=white)](https://discord.gg/BR8VGRrXFr) Join our community to discuss ideas, get support, and connect with other users.
745
+
746
+ [![Telegram](https://img.shields.io/badge/Telegram-26A5E4?logo=telegram&logoColor=white)](https://t.me/+6e2MtXxoibM2Yzlk) Receive instant updates and engage in real-time discussions.
747
+
748
+ ## See Also
749
+
750
+ We recommend exploring related tools and projects that can enhance your trading workflows:
751
+
752
+ - **[Nexus](https://github.com/Quantweb3-ai/nexus):** A robust exchange interface optimization solution that integrates
753
+ seamlessly with trading bots like nexustrader, enabling faster and more reliable trading execution.
754
+
755
+ ## License
756
+
757
+ Nexustrader is available on GitHub under the MIT License. Contributions to the project are welcome and require the
758
+ completion of a Contributor License Agreement (CLA). Please review the contribution guidelines and submit a pull
759
+ request. See the [LICENSE](./LICENSE) file for details.
760
+
761
+ ## Star History
762
+
763
+ <a href="https://www.star-history.com/#Quantweb3-com/NexusTrader&Date">
764
+ <picture>
765
+ <source media="(prefers-color-scheme: dark)" srcset="https://api.star-history.com/svg?repos=Quantweb3-com/NexusTrader&type=Date&theme=dark" />
766
+ <source media="(prefers-color-scheme: light)" srcset="https://api.star-history.com/svg?repos=Quantweb3-com/NexusTrader&type=Date" />
767
+ <img alt="Star History Chart" src="https://api.star-history.com/svg?repos=Quantweb3-com/NexusTrader&type=Date" />
768
+ </picture>
769
+ </a>