├── .github └── workflows │ └── deploy.yml ├── .gitignore ├── README.md ├── README.zh-CN.md ├── docs ├── .vitepress │ ├── config.js │ └── theme │ │ ├── custom.css │ │ └── index.js ├── README.md ├── config.md ├── developer.md ├── faq.md ├── index.md ├── market.md ├── operation.md ├── panacea.md ├── public │ └── images │ │ ├── desktop.jpg │ │ ├── desktop_cn.jpg │ │ ├── logo.png │ │ ├── screenshot.jpg │ │ ├── screenshot_cn.jpg │ │ ├── screenshot_large.jpg │ │ ├── screenshot_large_zh.jpg │ │ ├── screenshot_mobile.jpg │ │ ├── screenshot_mobile_zh.jpg │ │ ├── screenshot_zh.jpg │ │ ├── web_top.png │ │ └── web_top_en.png ├── status.md ├── strategy.md └── zh │ ├── README.md │ ├── config.md │ ├── developer.md │ ├── faq.md │ ├── index.md │ ├── market.md │ ├── operation.md │ ├── panacea.md │ ├── status.md │ └── strategy.md ├── extensions └── xcoin │ ├── README.md │ ├── README.zh-CN.md │ └── panacea │ ├── api │ ├── api.js │ ├── backtest.js │ ├── config.js │ ├── market.js │ ├── operation.js │ ├── panacea.js │ ├── status.js │ └── strategy.js │ └── index.js ├── package.json └── yarn.lock /.github/workflows/deploy.yml: -------------------------------------------------------------------------------- 1 | name: Deploy 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | 8 | jobs: 9 | deploy: 10 | runs-on: ubuntu-latest 11 | steps: 12 | - uses: actions/checkout@v3 13 | - uses: actions/setup-node@v3 14 | with: 15 | node-version: 16 16 | cache: yarn 17 | - run: yarn install --frozen-lockfile 18 | 19 | - name: Build 20 | run: yarn docs:build 21 | 22 | - name: Deploy 23 | uses: peaceiris/actions-gh-pages@v3 24 | with: 25 | github_token: ${{ secrets.GITHUB_TOKEN }} 26 | publish_dir: docs/.vitepress/dist -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | lerna-debug.log* 8 | 9 | # Diagnostic reports (https://nodejs.org/api/report.html) 10 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json 11 | 12 | # Runtime data 13 | pids 14 | *.pid 15 | *.seed 16 | *.pid.lock 17 | 18 | # Directory for instrumented libs generated by jscoverage/JSCover 19 | lib-cov 20 | 21 | # Coverage directory used by tools like istanbul 22 | coverage 23 | *.lcov 24 | 25 | # nyc test coverage 26 | .nyc_output 27 | 28 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) 29 | .grunt 30 | 31 | # Bower dependency directory (https://bower.io/) 32 | bower_components 33 | 34 | # node-waf configuration 35 | .lock-wscript 36 | 37 | # Compiled binary addons (https://nodejs.org/api/addons.html) 38 | build/Release 39 | 40 | # Dependency directories 41 | node_modules/ 42 | jspm_packages/ 43 | 44 | # TypeScript v1 declaration files 45 | typings/ 46 | 47 | # TypeScript cache 48 | *.tsbuildinfo 49 | 50 | # Optional npm cache directory 51 | .npm 52 | 53 | # Optional eslint cache 54 | .eslintcache 55 | 56 | # Microbundle cache 57 | .rpt2_cache/ 58 | .rts2_cache_cjs/ 59 | .rts2_cache_es/ 60 | .rts2_cache_umd/ 61 | 62 | # Optional REPL history 63 | .node_repl_history 64 | 65 | # Output of 'npm pack' 66 | *.tgz 67 | 68 | # Yarn Integrity file 69 | .yarn-integrity 70 | 71 | # dotenv environment variables file 72 | .env 73 | .env.test 74 | 75 | # parcel-bundler cache (https://parceljs.org/) 76 | .cache 77 | 78 | # Next.js build output 79 | .next 80 | 81 | # Nuxt.js build / generate output 82 | .nuxt 83 | dist 84 | 85 | # Gatsby files 86 | .cache/ 87 | # Comment in the public line in if your project uses Gatsby and *not* Next.js 88 | # https://nextjs.org/blog/next-9-1#public-directory-support 89 | # public 90 | 91 | # vuepress build output 92 | .vuepress/dist 93 | 94 | # Serverless directories 95 | .serverless/ 96 | 97 | # FuseBox cache 98 | .fusebox/ 99 | 100 | # DynamoDB Local files 101 | .dynamodb/ 102 | 103 | # TernJS port file 104 | .tern-port 105 | 106 | /test 107 | /docs/.vitepress/cache 108 | /docs/.vitepress/dist -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

Panacea

2 | 3 |

Panacea

4 | 5 |

Trading Bot Real-time Status Manager

6 |

Web Demo | Docs | Desktop | Mobile

7 | 8 | **Manage your trading bot anytime anywhere** 9 | 10 | > server side: XCoin,freqtrade,Zenbot or your own bot. 11 | > 12 | > client side: Android,Ios,Web,Linux, macOS and Windows. 13 | 14 | ## Screenshots 15 | 16 | ### Desktop 17 | 18 | ![Screenshot](docs/public/images/screenshot.jpg) 19 | 20 | ### Mobile 21 | 22 | ![Screenshot](docs/public/images/screenshot_mobile.jpg) 23 | 24 | ## Features 25 | 26 | - Support multiple open source trading bot or commercial trading bot 27 | - Support all platform(android,ios,web,windows,mac,linux) 28 | - Support multiple trading bot manage. 29 | - Support real-time trading, long short trading. 30 | - Support real-time modification of bot configuration. 31 | - Support real-time modification of bot strategies. 32 | 33 | ## Install 34 | 35 | ### Application 36 | 37 | Download application from the official website according to your needs [Desktop](https://www.ciiat.com/download) or [Mobile](https://www.ciiat.com/download) 38 | 39 | ### Developer 40 | 41 | ```bash 42 | git clone https://github.com/markmind/panacea-api.git 43 | ``` 44 | 45 | ## Document 46 | 47 | You can use or participate in development through the Panacea user documentation and developer documentation 48 | 49 | - [User Document](docs/README.md) 50 | 51 | - [Developer](docs/developer.md) 52 | 53 | If you have problems and bugs, please submit them through Github, We will try our best to answer your questions in time. Of course, it would be greatly appreciated if you could submit a PR directly. 54 | 55 | You can click here to view the [中文](README.zh-CN.md) document 56 | 57 | ## Contributors 58 | 59 | Thanks to all contributors [[contributors](https://github.com/markmind/panacea-api/graphs/contributors)] who participated to Panacea project. 60 | 61 | ## License 62 | 63 | [**MIT**](https://opensource.org/licenses/MIT). 64 | -------------------------------------------------------------------------------- /README.zh-CN.md: -------------------------------------------------------------------------------- 1 |

灵丹

2 | 3 |

灵丹

4 | 5 |

交易机器人实时状态管理

6 |

网页演示 | 文档 | 桌面版 | 移动版

7 | 8 | **随时随地管理您的交易机器人** 9 | 10 | > 服务器端: XCoin,freqtrade,Zenbot 或您自己创建的机器人. 11 | > 12 | > 客户端: Android,Ios,Web,Linux,macOS and Windows. 13 | 14 | ## 屏幕截图 15 | 16 | ### 桌面 17 | 18 | ![Screenshot](docs/public/images/screenshot_cn.jpg) 19 | 20 | ### 移动设备 21 | 22 | ![Screenshot](docs/public/images/screenshot_mobile_zh.jpg) 23 | 24 | ## 功能特征 25 | 26 | - 提供统一API,支持多种开源交易机器人或商业闭源机器人. 27 | - 支持所有客户端,任意时间,任意地点管理您的交易. 28 | - 支持管理多个机器人,一键切换 29 | - 支持实时交易,支持多空操作,支持买卖点显示 30 | - 支持配置参数实时修改 31 | - 支持策略参数实时修改 32 | 33 | ## 安装 34 | 35 | ### 客户端安装 36 | 37 | 根据您的需要官网下载 [桌面版](https://www.ciiat.com/download) 或 [移动版](https://www.ciiat.com/download) 灵丹程序 38 | 39 | ### 扩展开发 40 | 41 | ```bash 42 | git clone https://github.com/markmind/panacea-api.git 43 | ``` 44 | 45 | ## 文档 46 | 47 | 您可以通过用户文档与开发者文档了解灵丹的运行机制及参与开发. 48 | 49 | - [用户文档](docs/zh/README.md) 50 | 51 | - [开发者](docs/zh/developer.md) 52 | 53 | 如果您有使用上的问题与Bug,欢迎通过 Github 提交,我们会尽量及时回答您的问题。当然,如果您能够直接提交PR,我们将不胜感谢。 54 | 55 | 您可以点击这儿查看 [English](README.md) 文档. 56 | 57 | ## 贡献者 58 | 59 | 感谢所有参与灵丹项目的贡献者[[贡献者](https://github.com/markmind/panacea-api/graphs/contributors)]. 60 | 61 | ## License 62 | 63 | [**MIT**](https://opensource.org/licenses/MIT). 64 | -------------------------------------------------------------------------------- /docs/.vitepress/config.js: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'vitepress'; 2 | 3 | export default defineConfig({ 4 | title: 'Panacea', 5 | description: 'Trading Bot Real-time Status Manager', 6 | appearance: 'dark', 7 | base: '/panacea-api/', 8 | lastUpdated: true, 9 | ignoreDeadLinks: true, 10 | cleanUrls: 'true', 11 | markdown: { 12 | theme: 'material-theme-palenight', 13 | lineNumbers: false 14 | }, 15 | locales: { 16 | zh: { 17 | label: '简体中文', 18 | lang: 'zh-CN', 19 | link: '/zh/', 20 | title: "灵丹", 21 | description: '交易机器人实时状态管理', 22 | themeConfig: { 23 | siteTitle: '灵丹', 24 | nav: nav_cn(), 25 | docFooter: { 26 | prev: '上一页', 27 | next: '下一页' 28 | }, 29 | outlineTitle: '在此页', 30 | editLink: { 31 | pattern: 'https://github.com/markmind/panacea-api/docs/:path', 32 | text: '在GitHub上编辑此页面' 33 | }, 34 | footer: { 35 | message: 'MIT 授权', 36 | copyright: '版权所有 © 2023 Ciiat Tech' 37 | }, 38 | darkModeSwitchLabel: '外观', 39 | sidebarMenuLabel: '菜单', 40 | returnToTopLabel: '返回页首', 41 | langMenuLabel: '改变语言', 42 | lastUpdatedText: '最后更新' 43 | } 44 | }, 45 | root: { 46 | label: 'English', 47 | lang: 'en-US', 48 | link: '/' 49 | } 50 | }, 51 | 52 | // theme related configurations. 53 | themeConfig: { 54 | logo: '/images/logo.png', 55 | siteTitle: 'Panacea', 56 | i18nRouting: true, 57 | aside: 'true', 58 | docFooter: { 59 | prev: 'Previous Page', 60 | next: 'Next Page' 61 | }, 62 | outlineTitle: 'On this page', 63 | editLink: { 64 | pattern: 'https://github.com/markmind/panacea-api/docs/:path', 65 | text: 'Edit this page on GitHub' 66 | }, 67 | darkModeSwitchLabel: 'Appearance', 68 | sidebarMenuLabel: 'Menu', 69 | returnToTopLabel: 'Return to top', 70 | langMenuLabel: 'Change Language', 71 | lastUpdatedText: 'Last Updated', 72 | outline: 'deep', 73 | nav: nav(), 74 | sidebar: { 75 | '/': sidebarGuide(), 76 | '/zh/': sidebarGuide_cn() 77 | }, 78 | footer: { 79 | message: 'Released under the MIT License', 80 | copyright: 'Copyright © 2023-present Ciiat Tech' 81 | }, 82 | /* algolia: { 83 | appId: '8J64VVRP8K', 84 | apiKey: 'a18e2f4cc5665f6602c5631fd868adfd', 85 | indexName: 'xcoin' 86 | }, */ 87 | socialLinks: [ 88 | { icon: 'github', link: 'https://github.com/markmind/panacea-api' } 89 | ] 90 | } 91 | }) 92 | 93 | function nav_cn() { 94 | return [ 95 | { text: '指南', link: '/zh/panacea.md' }, 96 | { text: 'API', link: '/zh/status.md' }, 97 | { text: '反馈', link: 'https://github.com/markmind/panacea-api/issues' } 98 | ] 99 | } 100 | 101 | function nav() { 102 | return [ 103 | { text: 'Guide', link: '/panacea.md' }, 104 | { text: 'API', link: '/status.md' }, 105 | { text: 'Feedback', link: 'https://github.com/markmind/panacea-api/issues' } 106 | ] 107 | } 108 | 109 | function sidebarGuide_cn() { 110 | return [ 111 | { 112 | text: '简介', 113 | collapsed: false, 114 | items: [ 115 | { text: '灵丹', link: '/zh/panacea' }, 116 | { text: '开发者', link: '/zh/developer' }, 117 | { text: '常见问题', link: '/zh/faq' }, 118 | ] 119 | }, 120 | { 121 | text: 'API', 122 | collapsed: false, 123 | items: [ 124 | { text: '状态', link: '/zh/status' }, 125 | { text: '操作', link: '/zh/operation' }, 126 | { text: '配置', link: '/zh/config' }, 127 | { text: '策略', link: '/zh/strategy' }, 128 | { text: '市场', link: '/zh/market' } 129 | ] 130 | } 131 | ] 132 | } 133 | 134 | function sidebarGuide() { 135 | return [ 136 | { 137 | text: 'Introduction', 138 | collapsed: false, 139 | items: [ 140 | { text: 'Panacea', link: '/panacea' }, 141 | { text: 'Developer', link: '/developer' }, 142 | { text: 'Faq', link: '/faq' }, 143 | ] 144 | }, 145 | { 146 | text: 'API', 147 | collapsed: false, 148 | items: [ 149 | { text: 'Status', link: '/status' }, 150 | { text: 'Operation', link: '/operation' }, 151 | { text: 'Config', link: '/config' }, 152 | { text: 'Strategy', link: '/strategy' }, 153 | { text: 'Market', link: '/market' } 154 | ] 155 | } 156 | ] 157 | } 158 | -------------------------------------------------------------------------------- /docs/.vitepress/theme/custom.css: -------------------------------------------------------------------------------- 1 | /* .vitepress/theme/custom.css colors */ 2 | :root { 3 | --vp-c-brand: #cddc39; 4 | --vp-c-brand-light: #f5d419; 5 | --vp-c-brand-lighter: #fddc99; 6 | --vp-c-brand-lightest: #fddc99; 7 | --vp-c-brand-dark: #535bf2; 8 | --vp-c-brand-darker: #454ce1; 9 | --vp-c-brand-dim: rgba(100, 108, 255, 0.08); 10 | } 11 | 12 | /* .vitepress/theme/custom.css home */ 13 | 14 | 15 | 16 | .VPImage.image-src { 17 | position: absolute; 18 | top: 50%; 19 | left: 50%; 20 | max-width: 320px; 21 | max-height: 320px; 22 | transform: translate(-50%, -50%); 23 | } 24 | 25 | @media (min-width: 640px) { 26 | .VPImage.image-src { 27 | max-width: 480px; 28 | max-height: 480px; 29 | } 30 | } 31 | 32 | @media (min-width: 960px) { 33 | .VPImage.image-src { 34 | max-width: 560px; 35 | max-height: 560px; 36 | } 37 | } -------------------------------------------------------------------------------- /docs/.vitepress/theme/index.js: -------------------------------------------------------------------------------- 1 | // .vitepress/theme/index.js 2 | import DefaultTheme from 'vitepress/theme'; 3 | import './custom.css'; 4 | export default DefaultTheme; 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /docs/README.md: -------------------------------------------------------------------------------- 1 | # User Document 2 | 3 | **Introduction:** 4 | 5 | - [Panacea](panacea.md) 6 | - [Developer](developer.md) 7 | - [Faq](faq.md) 8 | 9 | **API:** 10 | 11 | - [Status](status.md) 12 | - [Operation](operation.md) 13 | - [Config](config.md) 14 | - [Strategy](strategy.md) 15 | - [Market](market.md) 16 | -------------------------------------------------------------------------------- /docs/config.md: -------------------------------------------------------------------------------- 1 | # Config API 2 | 3 | Config API provides the necessary data for the configuration module of the client. Through the configuration module, all your configurations on the server can be updated in real time through the client. Currently includes the following APIs 4 | 5 | - init: gets configuration settings and configuration values 6 | - updateConfig: update configuration 7 | - updateSymbolFuture: update trading pair configuration 8 | 9 | ## Implementation 10 | 11 | > **Optional** 12 | > If API is not implemented, the client will not have a configuration module. 13 | > If API is not implemented, please set `hasConfig` to `false` in the `init` of the robot state in the state API 14 | 15 | ## Update process 16 | 17 | - Pass configuration settings and configuration values in the `init` event 18 | - Generate the UI interface on the client side through configuration settings 19 | - Modify the configuration through the UI interface and update the server-side value through `updateConfig` 20 | 21 | ## API List 22 | 23 | ### - init 24 | 25 | When using the configuration module, configuration settings and configuration parameters will be passed to the client through `init` 26 | 27 | #### Request 28 | 29 | > When use connects to the bot, data will push to client. 30 | > When device reconnection (such asresume event),data push to client. 31 | 32 | ```javascript 33 | { 34 | "action": "init", 35 | "apiKey":"YOUR API KEY" 36 | } 37 | ``` 38 | 39 | #### Response 40 | 41 | ```javascript 42 | { 43 | "options": { //Bot config ,all values are set buy config settings 44 | "strategy": "BollingerBands", 45 | "period": "10m", 46 | "debug": false 47 | ... 48 | }, 49 | "config": { //config settings,include group,subgroup and item 50 | "bot": [//bot group realted 51 | { 52 | "name": "strategy",//config item name such as strategy 53 | "type": "string",//config item type 54 | "value": "BollingerBands"//config item value 55 | }, 56 | { 57 | "name": "period",//config item name such as period 58 | "type": "array",//array list 59 | "list": [//list value 60 | "1m", 61 | "3m", 62 | "5m" 63 | ], 64 | "value": "5m" 65 | }, 66 | { 67 | "name": "debug",//config item name such as debug 68 | "type": "bool",//bool 69 | "value": false 70 | }, 71 | { 72 | "name": "other",//group name 73 | "type": "group"//config item is group 74 | }, 75 | { 76 | "name": "poll_scan_time",//config item ,such as poll timeout 77 | "type": "number",//config item type 78 | "step": [//config item step 79 | 1000,//min 80 | 60000,//max 81 | 500//step 82 | ], 83 | "value": 3000, 84 | "des": true//this item has description 85 | }, 86 | { 87 | "name": "black_list",//config item name ,such as black_list 88 | "type": "textarea",//config item type 89 | "value": 'binance.BTC-USDT,binance.AAB-USDt', //config item value 90 | "des": true 91 | }, 92 | ... 93 | ], 94 | "exchange": [], //exchange related config, 95 | "order": [], //order related config, 96 | "sellPoint": [], //sell point related config, 97 | "watch": [], //watch pool related config 98 | "paper":[],//papaer related config 99 | } 100 | } 101 | ``` 102 | 103 | ### - updateConfig 104 | 105 | Update config params and restart bot or not 106 | 107 | #### Request 108 | 109 | ```javascript 110 | { 111 | "action": "updateConfig", 112 | "restart": true, //should restart bot or not 113 | "data": { 114 | "period": "3m", //update params 115 | "buy_pct":30 //update params 116 | }, 117 | "apiKey": "YOUR API KEY" 118 | } 119 | ``` 120 | 121 | #### Response 122 | 123 | ```javascript 124 | { 125 | "action": "updateConfig", 126 | "data":Object, //response all params object 127 | "toast": "trade.updateConfigOk" //show toast message 128 | } 129 | ``` 130 | 131 | ### - updateSymbolFuture 132 | 133 | Update symbol future parmas,now support future leverage and future mode 134 | 135 | #### Request 136 | 137 | ```javascript 138 | { 139 | "action": "updateSymbolFuture", 140 | "symbol":"BTC-USDT", //pair 141 | "data":{ 142 | "type":"leverage",//marginMode or leverage 143 | "value":10 //type is marginMode ,value is cross or isolated 144 | }, 145 | "apiKey": "YOUR API KEY" 146 | } 147 | ``` 148 | 149 | #### Response 150 | 151 | ```javascript 152 | { 153 | "action": "updateSymbolFuture", 154 | "toast": "trade.updateSymbolFutureOk" 155 | } 156 | ``` 157 | 158 | > A sample config file for extension/xcoin 159 | 160 | ````json 161 | { 162 | "bot": [ 163 | { 164 | "name": "strategy", 165 | "type": "string", 166 | "value": "rain_sar" 167 | }, 168 | { 169 | "name": "period", 170 | "type": "array", 171 | "list": [ 172 | "1m", 173 | "3m", 174 | "5m", 175 | "15m", 176 | "30m", 177 | "1h", 178 | "2h", 179 | "4h", 180 | "8h", 181 | "12h", 182 | "1d", 183 | "3d", 184 | "1w" 185 | ], 186 | "value": "30m" 187 | }, 188 | { 189 | "name": "mode", 190 | "type": "array", 191 | "list": [ 192 | "live", 193 | "paper" 194 | ], 195 | "value": "live" 196 | }, 197 | { 198 | "name": "trade_type", 199 | "type": "array", 200 | "list": [ 201 | "auto", 202 | "autoBuy", 203 | "autoSell", 204 | "manual" 205 | ], 206 | "value": "live" 207 | }, 208 | { 209 | "name": "debug", 210 | "type": "bool", 211 | "value": false 212 | }, 213 | { 214 | "name": "other", 215 | "type": "group" 216 | }, 217 | { 218 | "name": "poll_scan_time", 219 | "type": "number", 220 | "step": [ 221 | 1000, 222 | 60000, 223 | 500 224 | ], 225 | "value": 3000, 226 | "des": true 227 | }, 228 | { 229 | "name": "poll_broadcast_time", 230 | "type": "number", 231 | "step": [ 232 | 3000, 233 | 60000, 234 | 1000 235 | ], 236 | "value": 5000, 237 | "des": true 238 | }, 239 | { 240 | "name": "save_bot_time", 241 | "type": "number", 242 | "step": [ 243 | 6000, 244 | 6000000, 245 | 6000 246 | ], 247 | "value": 600000, 248 | "des": true 249 | }, 250 | { 251 | "name": "min_periods", 252 | "type": "number", 253 | "step": [ 254 | 18, 255 | 500, 256 | 1 257 | ], 258 | "value": 32 259 | }, 260 | { 261 | "name": "keep_lookback_periods", 262 | "type": "number", 263 | "step": [ 264 | 50, 265 | 50000, 266 | 10 267 | ], 268 | "value": 500 269 | }, 270 | { 271 | "name": "price_format", 272 | "type": "string", 273 | "value": "0.00000000" 274 | }, 275 | { 276 | "name": "same_period_multi_buy", 277 | "type": "bool", 278 | "value": false 279 | }, 280 | { 281 | "name": "run_for", 282 | "type": "number", 283 | "step": [ 284 | 0, 285 | 1000, 286 | 1 287 | ], 288 | "value": 0, 289 | "des": true 290 | } 291 | ], 292 | "exchange": [ 293 | { 294 | "name": "exchange", 295 | "type": "array", 296 | "list": [ 297 | "binanceusdm", 298 | "binance", 299 | "mexc" 300 | ], 301 | "value": "binanceusdm" 302 | }, 303 | { 304 | "name": "takerFee", 305 | "type": "number", 306 | "step": [ 307 | 0.001, 308 | 0.5, 309 | 0.001 310 | ], 311 | "value": 0.1 312 | }, 313 | { 314 | "name": "makerFee", 315 | "type": "number", 316 | "step": [ 317 | 0.001, 318 | 0.5, 319 | 0.001 320 | ], 321 | "value": 0.1 322 | }, 323 | { 324 | "name": "future", 325 | "type": "group" 326 | }, 327 | { 328 | "name": "future", 329 | "type": "bool", 330 | "value": false, 331 | "readonly": true 332 | }, 333 | { 334 | "name": "market", 335 | "type": "array", 336 | "list": [ 337 | "only_long", 338 | "only_short", 339 | "both" 340 | ], 341 | "value": "only_long" 342 | }, 343 | { 344 | "name": "leverage", 345 | "type": "number", 346 | "step": [ 347 | 2, 348 | 125, 349 | 1 350 | ], 351 | "value": 10 352 | }, 353 | { 354 | "name": "marginMode", 355 | "type": "array", 356 | "list": [ 357 | "cross", 358 | "isolated" 359 | ], 360 | "value": "isolated" 361 | }, 362 | { 363 | "name": "short_buy_pct", 364 | "type": "number", 365 | "step": [ 366 | 0, 367 | 100, 368 | 1 369 | ], 370 | "value": 20 371 | }, 372 | { 373 | "name": "buy_position_side_when_sell", 374 | "type": "bool", 375 | "value": false 376 | } 377 | ], 378 | "order": [ 379 | { 380 | "name": "order_type", 381 | "type": "array", 382 | "list": [ 383 | "maker", 384 | "taker" 385 | ], 386 | "value": "maker" 387 | }, 388 | { 389 | "name": "max_slippage_pct", 390 | "type": "number", 391 | "step": [ 392 | 0.1, 393 | 2, 394 | 0.1 395 | ], 396 | "value": 0.5, 397 | "group": "core" 398 | }, 399 | { 400 | "name": "buy", 401 | "type": "group" 402 | }, 403 | { 404 | "name": "buy_pct", 405 | "type": "number", 406 | "step": [ 407 | 0, 408 | 100, 409 | 1 410 | ], 411 | "value": 20 412 | }, 413 | { 414 | "name": "min_buy_size", 415 | "type": "number", 416 | "step": [ 417 | 0, 418 | 100, 419 | 1 420 | ], 421 | "value": 10 422 | }, 423 | { 424 | "name": "max_buy_size", 425 | "type": "number", 426 | "step": [ 427 | 0, 428 | 10000, 429 | 100 430 | ], 431 | "value": 0 432 | }, 433 | { 434 | "name": "sell", 435 | "type": "group" 436 | }, 437 | { 438 | "name": "sell_pct", 439 | "type": "number", 440 | "step": [ 441 | 0, 442 | 100, 443 | 1 444 | ], 445 | "value": 100, 446 | "group": "sell" 447 | }, 448 | { 449 | "name": "other", 450 | "type": "group" 451 | }, 452 | { 453 | "name": "order_adjust_time", 454 | "type": "number", 455 | "step": [ 456 | 1000, 457 | 1000, 458 | 1000 459 | ], 460 | "value": 5000, 461 | "group": "other" 462 | }, 463 | { 464 | "name": "max_sell_loss_pct", 465 | "type": "number", 466 | "step": [ 467 | 0, 468 | 5, 469 | 0.5 470 | ], 471 | "value": 1, 472 | "group": "other" 473 | }, 474 | { 475 | "name": "max_buy_loss_pct", 476 | "type": "number", 477 | "step": [ 478 | 0, 479 | 5, 480 | 0.5 481 | ], 482 | "value": 1, 483 | "group": "other" 484 | }, 485 | { 486 | "name": "order_poll_time", 487 | "type": "number", 488 | "step": [ 489 | 1000, 490 | 60000, 491 | 1000 492 | ], 493 | "value": 5000, 494 | "group": "other" 495 | }, 496 | { 497 | "name": "wait_for_settlement", 498 | "type": "number", 499 | "step": [ 500 | 1000, 501 | 60000, 502 | 1000 503 | ], 504 | "value": 5000, 505 | "group": "other", 506 | "des": true 507 | }, 508 | { 509 | "name": "markdown_buy_pct", 510 | "type": "number", 511 | "step": [ 512 | 0, 513 | 5, 514 | 0.1 515 | ], 516 | "value": 0, 517 | "group": "other" 518 | }, 519 | { 520 | "name": "markup_sell_pct", 521 | "type": "number", 522 | "step": [ 523 | 0, 524 | 5, 525 | 0.1 526 | ], 527 | "value": 0, 528 | "group": "other" 529 | }, 530 | { 531 | "name": "post_only", 532 | "type": "bool", 533 | "value": false, 534 | "group": "other" 535 | }, 536 | { 537 | "name": "use_fee_asset", 538 | "type": "bool", 539 | "value": false, 540 | "group": "other" 541 | }, 542 | { 543 | "name": "avg_slippage_pct", 544 | "type": "number", 545 | "value": 0.045, 546 | "step": [ 547 | 0, 548 | 0.1, 549 | 0.005 550 | ], 551 | "group": "other" 552 | }, 553 | { 554 | "name": "quarentine_time", 555 | "type": "number", 556 | "step": [ 557 | 0, 558 | 100000, 559 | 1000 560 | ], 561 | "value": 0, 562 | "group": "other" 563 | } 564 | ], 565 | "sellPoint": [ 566 | { 567 | "name": "sell_stop_pct", 568 | "type": "number", 569 | "step": [ 570 | 0, 571 | 30, 572 | 0.1 573 | ], 574 | "value": 5 575 | }, 576 | { 577 | "name": "profitStop", 578 | "type": "group" 579 | }, 580 | { 581 | "name": "profit_stop_enable", 582 | "type": "bool", 583 | "value": true 584 | }, 585 | { 586 | "name": "profit_stop_percent", 587 | "type": "number", 588 | "step": [ 589 | 0, 590 | 100, 591 | 1 592 | ], 593 | "value": 50 594 | }, 595 | { 596 | "name": "profit_stop_first_rate", 597 | "type": "number", 598 | "step": [ 599 | 0, 600 | 500, 601 | 1 602 | ], 603 | "value": 10 604 | }, 605 | { 606 | "name": "profit_stop_first_percent", 607 | "type": "number", 608 | "step": [ 609 | 0, 610 | 100, 611 | 1 612 | ], 613 | "value": 30 614 | }, 615 | { 616 | "name": "profit_stop_second_rate", 617 | "type": "number", 618 | "step": [ 619 | 0, 620 | 500, 621 | 1 622 | ], 623 | "value": 20 624 | }, 625 | { 626 | "name": "profit_stop_second_percent", 627 | "type": "number", 628 | "step": [ 629 | 0, 630 | 100, 631 | 1 632 | ], 633 | "value": 40 634 | }, 635 | { 636 | "name": "profit_stop_third_rate", 637 | "type": "number", 638 | "step": [ 639 | 0, 640 | 500, 641 | 1 642 | ], 643 | "value": 50 644 | }, 645 | { 646 | "name": "profit_stop_third_percent", 647 | "type": "number", 648 | "step": [ 649 | 0, 650 | 100, 651 | 1 652 | ], 653 | "value": 50 654 | }, 655 | { 656 | "name": "profit_stop_max_rate", 657 | "type": "number", 658 | "step": [ 659 | 0, 660 | 500, 661 | 1 662 | ], 663 | "value": 100 664 | }, 665 | { 666 | "name": "profit_stop_max_percent", 667 | "type": "number", 668 | "step": [ 669 | 0, 670 | 100, 671 | 1 672 | ], 673 | "value": 70 674 | }, 675 | { 676 | "name": "profitSell", 677 | "type": "group" 678 | }, 679 | { 680 | "name": "profit_win_enable", 681 | "type": "bool", 682 | "value": true 683 | }, 684 | { 685 | "name": "profit_win_first_rate", 686 | "type": "number", 687 | "step": [ 688 | 0, 689 | 500, 690 | 1 691 | ], 692 | "value": 25 693 | }, 694 | { 695 | "name": "profit_win_first_percent", 696 | "type": "number", 697 | "step": [ 698 | 0, 699 | 100, 700 | 1 701 | ], 702 | "value": 50 703 | }, 704 | { 705 | "name": "profit_win_second_rate", 706 | "type": "number", 707 | "step": [ 708 | 0, 709 | 500, 710 | 1 711 | ], 712 | "value": 50 713 | }, 714 | { 715 | "name": "profit_win_second_percent", 716 | "type": "number", 717 | "step": [ 718 | 0, 719 | 100, 720 | 1 721 | ], 722 | "value": 50 723 | }, 724 | { 725 | "name": "profit_win_third_rate", 726 | "type": "number", 727 | "step": [ 728 | 0, 729 | 500, 730 | 1 731 | ], 732 | "value": 100 733 | }, 734 | { 735 | "name": "profit_win_third_percent", 736 | "type": "number", 737 | "step": [ 738 | 0, 739 | 100, 740 | 1 741 | ], 742 | "value": 50 743 | }, 744 | { 745 | "name": "profit_win_max_rate", 746 | "type": "number", 747 | "step": [ 748 | 0, 749 | 500, 750 | 1 751 | ], 752 | "value": 200 753 | }, 754 | { 755 | "name": "profit_win_max_percent", 756 | "type": "number", 757 | "step": [ 758 | 0, 759 | 100, 760 | 1 761 | ], 762 | "value": 50 763 | } 764 | ], 765 | "watch": [ 766 | { 767 | "name": "max_watch_size", 768 | "type": "number", 769 | "step": [ 770 | 0, 771 | 30, 772 | 5 773 | ], 774 | "value": 10 775 | }, 776 | { 777 | "name": "watch_symbols", 778 | "type": "textarea", 779 | "value": "", 780 | "placeholder": true 781 | }, 782 | { 783 | "name": "watchInit", 784 | "type": "group" 785 | }, 786 | { 787 | "name": "watch_include_bought", 788 | "type": "bool", 789 | "value": true 790 | }, 791 | { 792 | "name": "watch_with_black_list", 793 | "type": "bool", 794 | "value": true 795 | }, 796 | { 797 | "name": "black_list", 798 | "type": "textarea", 799 | "value": "", 800 | "placeholder": true 801 | } 802 | ], 803 | "paper": [ 804 | { 805 | "name": "currency_capital", 806 | "type": "number", 807 | "step": [ 808 | 0, 809 | 10000, 810 | 1000 811 | ], 812 | "value": 1000 813 | }, 814 | { 815 | "name": "asset_capital", 816 | "type": "number", 817 | "step": [ 818 | 0, 819 | 10000, 820 | 1000 821 | ], 822 | "value": 0 823 | } 824 | ] 825 | } 826 | ```` 827 | -------------------------------------------------------------------------------- /docs/developer.md: -------------------------------------------------------------------------------- 1 | # Developer 2 | 3 | Panacea provides a easy way to manage your real-time trading bot status. You can adapt to your own bots by developing extensions. Your are welcome to add extensions based on Freqtrade, Zenbot, and others 4 | 5 | ## Development process 6 | 7 | 1. Understand the Panacea API and decide which APIs you need to adapt to 8 | 9 | 2. Add an extension based on Panacea to your bot code 10 | 11 | 3. Download the Panacea application [Download Panacea](https://www.ciiat.com/en/download) and add your trading bot for testing 12 | 13 | 4. You can also directly use the [Web version of Panacea](https://www.ciiat.com/app/www) Directly add your trading bot for testing 14 | 15 | 5. Download the Panacea API code and place your relevant code in the 'extensions' directory 16 | 17 | ```bash 18 | git clone https://github.com/markmind/panacea-api.git 19 | ``` 20 | 21 | 6. Submit a PR and we will merge as soon as possible 22 | 23 | ## Precautions 24 | 25 | - When adding code, it is necessary to add the README.md file in the root directory to help users understand the details of using the extension 26 | - All extensions need to follow 'MIT' license 27 | - You can download and run [XCoin](https://github.com/rianfu/xcoin) to learn how to use api. 28 | -------------------------------------------------------------------------------- /docs/faq.md: -------------------------------------------------------------------------------- 1 | # FAQ 2 | 3 | Here are some frequently asked questions and responses from the community. 4 | 5 | If you have a question that isn't answered here, please ask it in the community 6 | 7 | Thanks! 8 | 9 | ## Question 10 | 11 | ### [Develop](#develop) 12 | 13 | ## Answer 14 | 15 | ### Develop 16 | -------------------------------------------------------------------------------- /docs/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: home 3 | 4 | hero: 5 | name: Panacea 6 | text: Trading Bot Real-time Status Manager 7 | tagline: Manage your trading bot anytime, anywhere 8 | image: 9 | src: /images/web_top_en.png 10 | alt: Panacea 11 | 12 | actions: 13 | - theme: brand 14 | text: Get Started 15 | link: /panacea 16 | - theme: sponsor 17 | text: Demo 18 | link: https://www.ciiat.com/app/www 19 | - theme: sponsor 20 | text: Download 21 | link: https://www.ciiat.com/en/download 22 | - theme: alt 23 | text: View on GitHub 24 | link: https://github.com/markmind/panacea-api 25 | 26 | features: 27 | - title: Provide Unified API 28 | details: Support multiple open source trading bot or commercial trading bots. 29 | - title: Supports all platform 30 | details: Manage your transactions anytime, anywhere on your desktop or mobile device. 31 | - title: Multi trading bot management 32 | details: Supports managing multiple bot with one click switching. 33 | - title: Support real-time trading 34 | details: Support long short operations and display of buying and selling points。 35 | - title: Supports real-time modification of configuration 36 | details: Support changing parameters at runtime and remote start stop to apply parameters 37 | - title: Supports real-time modification of strategies 38 | details: Support changing strategies or adjusting strategy parameters at runtime, and support remote start stop to use new strategy. 39 | --- 40 | -------------------------------------------------------------------------------- /docs/market.md: -------------------------------------------------------------------------------- 1 | # Market API 2 | 3 | Market API provide data for client market module,Inclues APIs 4 | 5 | - getProducts Get products 6 | - getTickers Get products tickers 7 | - getKlines Get kline for symbol 8 | - getPickerNormal Get hot products in exchange 9 | 10 | ## Implementation 11 | 12 | >**Optional** 13 | >If this API is not implemented, the client will not have a market module 14 | >If this API is not implemented, please set `hasMarket` to `false` in the `init` of the bot's status` 15 | 16 | ## API List 17 | 18 | ### - getProducts 19 | 20 | Get all products in bot exchange 21 | 22 | #### Request 23 | 24 | ```javascript 25 | { 26 | "action": "getProducts", 27 | "apiKey":"YOUR API KEY" 28 | } 29 | ``` 30 | 31 | #### Response 32 | 33 | ```javascript 34 | { 35 | "action": "getProducts", 36 | "data":[{ 37 | "id": "1INCH_USDT", //pair id 38 | "asset": "1INCH",//asset 39 | "currency": "USDT",//currency 40 | "active": true, 41 | "min_size": "0.01",//min asset size 42 | "increment": "0.0001",//price increment 43 | "asset_increment": "0.01",//asset increment 44 | "label": "1INCH/USDT", 45 | "exchagne_id": "mexc", 46 | "product_id": "1INCH-USDT", 47 | "normalized": "mexc.1INCH-USDT" 48 | }, 49 | ... 50 | ] 51 | } 52 | ``` 53 | 54 | ### - getTickers 55 | 56 | Get tickers for request symbols or all products in exchange, 57 | 58 | > response all products tickers when no symbols input 59 | 60 | #### Request 61 | 62 | ```javascript 63 | { 64 | "action": "getTickers", 65 | "data": { 66 | "symbols": [ 67 | { 68 | "product_id": "1INCH-USDT" 69 | }, 70 | ... 71 | ] 72 | }, 73 | "apiKey": "YOUR API KEY" 74 | } 75 | ``` 76 | 77 | #### Response 78 | 79 | ```javascript 80 | { 81 | "action": "getTickers", 82 | "data": [ 83 |     { 84 |     "symbol": "GDO/USDT",//symbol name 85 |     "price": 8.98e-8, //real-time price 86 |     "percentage": 1 //24hr price changed rate 87 |     } 88 |     ... 89 | ] 90 | } 91 | ``` 92 | 93 | ### - getPickerNormal 94 | 95 | Get hot products in the bot exchange 96 | 97 | > Get some featured products ,such as Maximum amplitude... 98 | 99 | #### Request 100 | 101 | ```javascript 102 | { 103 | "action": "getPickerNormal", 104 | "data": { 105 | "period": "1d", //kline period 106 | "limit": 10,// result data length 107 | "number": 8 //min kline data length 108 | }, 109 | "apiKey": "YOUR API KEY" 110 | } 111 | ``` 112 | 113 | #### Response 114 | 115 | ```javascript 116 | { 117 | "action": "getPickerNormal", 118 | "data": { 119 | "maxSum": [//Maximum amplitude 120 | { 121 | "index": 1, //order 122 | "product_id": "ARB-USDT", 123 | "price": 1.3181, 124 | "extra": "12400.37%", //Total amplitude rate 125 | "klines": [ 126 | { 127 | "time": 1679529600000, 128 | "close": 1.3181 129 | } 130 | ... 131 | ] 132 | } 133 | ... 134 | ], 135 | "minSum": [//Minimum amplitude 136 | { 137 | "index": 1,//order 138 | "product_id": "BUSD-USDT", 139 | "price": 0.9982, 140 | "extra": "2.04%", //Total amplitude rate 141 | "klines": [ 142 | { 143 | "time": 1678752000000, 144 | "close": 0.9965 145 | }, 146 | ... 147 | ] 148 | }, 149 | ... 150 | ], 151 | "fastUp": [//Maximum Up 152 | { 153 | "index": 1,//order 154 | "product_id": "ID-USDT", 155 | "price": 0.5285, 156 | "extra": "2014.00%",//total up rate 157 | "klines": [ 158 | { 159 | "time": 1679443200000, 160 | "close": 0.40696 161 | }, 162 | ... 163 | ] 164 | }, 165 | ... 166 | ], 167 | "moreUp": [//More up 168 | { 169 | "index": 1,// order 170 | "product_id": "LOOP-USDT", 171 | "price": 0.12923, 172 | "extra": "9/10",// up line length 173 | "klines": [ 174 | { 175 | "time": 1679529600000, 176 | "close": 0.12923 177 | }, 178 | ... 179 | ] 180 | }, 181 | ... 182 | ], 183 | "continueUp": [//Continue Up 184 | { 185 | "index": 1, //order 186 | "product_id": "LOOP-USDT", 187 | "price": 0.12923, 188 | "extra": 9, //continue up length 189 | "klines": [ 190 | { 191 | "time": 1678752000000, 192 | "close": 0.03596 193 | }, 194 | ... 195 | ], 196 | ... 197 | } 198 | ] 199 | } 200 | } 201 | ``` 202 | 203 | ### getKlines 204 | 205 | Get klines for symbol 206 | 207 | #### Request 208 | 209 | ```javascript 210 | { 211 | "action": "getKlines", 212 | "symbol": "ALGO-USDT", //symbol 213 | "data": { 214 | "product_id": "ALGO-USDT", 215 | "limit": 60, //kline data length 216 | "period": "30m" //kline period 217 | }, 218 | "apiKey": "YOUR API KEY" 219 | } 220 | ``` 221 | 222 | #### Response 223 | 224 | ```javascript 225 | { 226 | "action": "getKlines", 227 | "data": { 228 | "period": "30m", //kline period 229 | "klines": [ 230 | { 231 | "period_id": "30m933888",//kline id 232 | "time": 1680768000,//kline start time 233 | "size": "30m",//period 234 | "close_time": 1681000199999,//kline close time 235 | "open": 0.216, 236 | "high": 0.2169, 237 | "low": 0.2157, 238 | "close": 0.2169, 239 | "volume": 12943.41 240 | } 241 | ... 242 | ] 243 | } 244 | } 245 | ``` 246 | -------------------------------------------------------------------------------- /docs/operation.md: -------------------------------------------------------------------------------- 1 | # Operation API 2 | 3 | Operation API provide interaction with the server, which can be divided into several types according to different functions 4 | 5 | - Watch symbols 6 | - addSymbol 7 | - removeSymbol 8 | - removeAllSymbol 9 | - Trade for symbol 10 | - buy 11 | - sell 12 | - sellAll 13 | 14 | ## Implementation 15 | 16 | > **Must** 17 | 18 | ## API List 19 | 20 | ### - addSymbol 21 | 22 | Add new symbol to watch symbols 23 | 24 | #### Request 25 | 26 | ```javascript 27 | { 28 | "action": "addSymbol", 29 | "symbols": [ 30 | "mexc.ACM-USDT" //add symbol name 31 | ], 32 | "data": {}, 33 | "apiKYOUR API KEYJYOyKq" 34 | } 35 | ``` 36 | 37 | #### Response 38 | 39 | ```javascript 40 | { 41 | "action": "addSymbol", 42 | "toast": "trade.addSymbolOk",//toast to show 43 | "data": { 44 | "success": true 45 | } 46 | } 47 | ``` 48 | 49 | ### - removeSymbol 50 | 51 | Remove symbols for watch symbols, 52 | 53 | #### Request 54 | 55 | ```javascript 56 | { 57 | "action": "removeSymbol", 58 | "symbol": "mexc.ETH-USDT", //remove symbol name 59 | "apiKey": "YOUR API KEY" 60 | } 61 | ``` 62 | 63 | #### Response 64 | 65 | ```javascript 66 | { 67 | "action": "removeSymbol", 68 | "toast": "trade.removeSymbolOk", 69 | "data": { 70 | "success": true 71 | } 72 | } 73 | ``` 74 | 75 | ### - removeAllSymbol 76 | 77 | Remove all symbols from watch symbols 78 | 79 | #### Request 80 | 81 | ```javascript 82 | { 83 | "action": "removeAllSymbol", 84 | "apiKey": "YOUR API KEY" 85 | } 86 | ``` 87 | 88 | #### Response 89 | 90 | ```javascript 91 | { 92 | "action": "removeAllSymbol", 93 | "toast": "trade.removeAllSymbolOk" 94 | } 95 | ``` 96 | 97 | ### buy 98 | 99 | buy symbol 100 | 101 | #### Request 102 | 103 | ```javascript 104 | { 105 | "action": "buy", 106 | "symbol": "BTC-USDT", 107 | "data": { 108 | "position_side": "LONG", //LONG buy OR SHORT buy 109 | "size":20//buy size 110 | }, 111 | "apiKey": "YOUR API KEY" 112 | } 113 | ``` 114 | 115 | #### Response 116 | 117 | ```javascript 118 | { 119 | "action": "buy", 120 | "toast": "trade.buyOk" //toast to show 121 | } 122 | ``` 123 | 124 | ### -Sell 125 | 126 | sell symbol 127 | 128 | #### Request 129 | 130 | ```javascript 131 | { 132 | "action": "sell", 133 | "symbol": "BTC-USDT", 134 | "data": { 135 | "position_side": "LONG", //LONG sell OR SHORT sell 136 | "size":20// sell size 137 | }, 138 | "apiKey": "YOUR API KEY" 139 | } 140 | ``` 141 | 142 | #### Response 143 | 144 | ```javascript 145 | { 146 | "action": "sell", 147 | "toast": "trade.sellOk" //toast to show 148 | } 149 | ``` 150 | 151 | ### - sellAll 152 | 153 | sell all symbols 154 | 155 | #### Request 156 | 157 | ```javascript 158 | { 159 | "action": "sellAll", 160 | "apiKey": "YOUR API KEY" 161 | } 162 | ``` 163 | 164 | #### Response 165 | 166 | ```javascript 167 | { 168 | "action": "sellAll", 169 | "toast": "trade.sellAllOk" //toast to show 170 | } 171 | ``` 172 | -------------------------------------------------------------------------------- /docs/panacea.md: -------------------------------------------------------------------------------- 1 | # About Panacea 2 | 3 | Panacea expands the functions of your trading bot through a simple method, allowing you to control and observe your bot at any time and any place through desktop or mobile devices, through the status, operation, config, strategy, etc. you can find out the ideal trading method more quickly and reasonably, greatly reducing the risk of quantitative trading and improving the profitability of trading. 4 | 5 | ## Screenshot 6 | 7 | ### Desktop 8 | 9 | includes Windows,Osx and Linux client 10 | 11 | ![Desktop](/images/desktop.jpg) 12 | 13 | ### Mobile 14 | 15 | includes Android and Ios client 16 | 17 | ![Mobile](/images/screenshot_mobile.jpg) 18 | 19 | Before you can adapt your trading bot to Panacea, there are a few things you need to know about how we work. 20 | 21 | ## Page Architecture 22 | 23 | Depending on what you implement the API, Panacea will display different page content 24 | 25 | > Status and Operation API is the core function of panacea that must be implemented 26 | > If you do not implement the configuration function, the panacea configuration module will not be enabled 27 | 28 | - bot 29 | - Bot management 30 | - Config management 31 | - Strategy management 32 | - Watch list 33 | - Trading pair 34 | - Trading history 35 | - market 36 | - Trading pair list 37 | - Trading pair 38 | - Hot products 39 | 40 | ## API support 41 | 42 | - Bot status `Required` 43 | - Bot operation `Required` 44 | - Bot config `Optional` 45 | - Bot strategy `Optional` 46 | - Bot Exchange Market `Optional` 47 | -------------------------------------------------------------------------------- /docs/public/images/desktop.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/markmind/panacea-api/ac40fc5d3657019cbf7ae306d34024dd880be7b5/docs/public/images/desktop.jpg -------------------------------------------------------------------------------- /docs/public/images/desktop_cn.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/markmind/panacea-api/ac40fc5d3657019cbf7ae306d34024dd880be7b5/docs/public/images/desktop_cn.jpg -------------------------------------------------------------------------------- /docs/public/images/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/markmind/panacea-api/ac40fc5d3657019cbf7ae306d34024dd880be7b5/docs/public/images/logo.png -------------------------------------------------------------------------------- /docs/public/images/screenshot.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/markmind/panacea-api/ac40fc5d3657019cbf7ae306d34024dd880be7b5/docs/public/images/screenshot.jpg -------------------------------------------------------------------------------- /docs/public/images/screenshot_cn.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/markmind/panacea-api/ac40fc5d3657019cbf7ae306d34024dd880be7b5/docs/public/images/screenshot_cn.jpg -------------------------------------------------------------------------------- /docs/public/images/screenshot_large.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/markmind/panacea-api/ac40fc5d3657019cbf7ae306d34024dd880be7b5/docs/public/images/screenshot_large.jpg -------------------------------------------------------------------------------- /docs/public/images/screenshot_large_zh.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/markmind/panacea-api/ac40fc5d3657019cbf7ae306d34024dd880be7b5/docs/public/images/screenshot_large_zh.jpg -------------------------------------------------------------------------------- /docs/public/images/screenshot_mobile.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/markmind/panacea-api/ac40fc5d3657019cbf7ae306d34024dd880be7b5/docs/public/images/screenshot_mobile.jpg -------------------------------------------------------------------------------- /docs/public/images/screenshot_mobile_zh.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/markmind/panacea-api/ac40fc5d3657019cbf7ae306d34024dd880be7b5/docs/public/images/screenshot_mobile_zh.jpg -------------------------------------------------------------------------------- /docs/public/images/screenshot_zh.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/markmind/panacea-api/ac40fc5d3657019cbf7ae306d34024dd880be7b5/docs/public/images/screenshot_zh.jpg -------------------------------------------------------------------------------- /docs/public/images/web_top.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/markmind/panacea-api/ac40fc5d3657019cbf7ae306d34024dd880be7b5/docs/public/images/web_top.png -------------------------------------------------------------------------------- /docs/public/images/web_top_en.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/markmind/panacea-api/ac40fc5d3657019cbf7ae306d34024dd880be7b5/docs/public/images/web_top_en.png -------------------------------------------------------------------------------- /docs/status.md: -------------------------------------------------------------------------------- 1 | # Status API 2 | 3 | Status API provides the necessary data for the bot module of the client, currently includes the following APIs 4 | 5 | - init:get all bot initial data 6 | - refresh:get bot update data 7 | 8 | ## Implementation 9 | 10 | > **Required** 11 | > When the server uses websocket communication, `init` will get all the initial data and initialize the client, and websocket will continuously pass `refrsh` data to the client through broadcasting 12 | 13 | ## API List 14 | 15 | ### - init 16 | 17 | Get all current bot init data 18 | 19 | #### Request 20 | 21 | > When user successfully connects to the bot, data will be pushed to client. 22 | > When device reconnection (such as resume event), data will be pushed to client again. 23 | 24 | ```javascript 25 | { 26 | "action": "init", 27 | "apiKey":"YOUR API KEY" 28 | } 29 | ``` 30 | 31 | #### Response 32 | 33 | ```javascript 34 | { 35 | "exchange": { //exchange 36 | "name": "sim", //name 'sim' is paper trading 37 | "makerFee": 0.1, //exchange maker fee 38 | "takerFee": 0.1//exchange taker fee 39 | }, 40 | "symbols": [ // watch symbols 41 | { 42 | "product_id": "ETH-USDT", //pair name 43 | "price": 1858.08, //pair price 44 | "normalized": "mexc.ETH-USDT",//pair full name 45 | "min_size": "0.00001",//pair min size 46 | "asset": "ETH", 47 | "currency": "USDT", 48 | "assetCaptial": 0, 49 | "leverage": 10,//future leverage 50 | "isolated": false,//future mode 51 | "usdtProfit": 0,//USDT profit 52 | "dynamicProfit": 0,//unrealized USDT profit 53 | "dynamicUsdtProfit": 0,//unrealized USDT profit rate 54 | "profit": 0,//USDT profit reate 55 | "signal": null,//signal include 'buying','selling','bought','sold' 56 | "win": 0,//win count 57 | "lost": 0,//lost count 58 | "winLostRate": 0,//win rate 59 | "trades": [{//pair order list 60 | "order_id": 1001, //order ID 61 | "time": 1681111866476,//order time 62 | "execution_time": 5001,//order execution time 63 | "slippage": 0,//order slippage 64 | "type": "buy",//order position type, buy or sell 65 | "size": "0.10757",//order size 66 | "fee": 0.19980051799999998,//order fee usdt 67 | "price": "1857.40", //order price 68 | "order_type": "maker",//order type 'maker' or 'taker' 69 | "action": "BollingerBands_buy_long",//order buy or send strategy type 70 | "profit": -0.0009999999999999998, //order porfit 71 | "usdtProfit": -0.19980051799999998,//order profit rate 72 | "position_side": "long",//order position side 'long' or 'short' 73 | }, 74 | ... 75 | ], 76 | "lastTradeTime": 0,//last trade time 77 | "klines": [//kline data 78 | { 79 | "period_id": "m28018427", 80 | "time": 1681105620000, 81 | "size": "1m", 82 | "close_time": 1681105679999, 83 | "open": 1863.3, 84 | "high": 1863.38, 85 | "low": 1862.22, 86 | "close": 1862.22, 87 | "volume": 45.16688, 88 | "strategy": { //kline data straegy 89 | "BollingerBands_buyCrossCount": 0,//bb buy point count in this period 90 | "BollingerBands_sellCrossCount": 1,//bb sell point count in this period 91 | "BollingerBands_buy": false,//if bb has buy point 92 | "BollingerBands_sell": false//if bb has sell point 93 | } 94 | }, 95 | ... 96 | ] 97 | }, 98 | ... 99 | ], 100 | "status": { //bot status 101 | "hasConfig": true,//if has config module 102 | "hasStrategy": true,//if has strategy module 103 | "hasMarket": true,//if has market module 104 | "hasBacktest": true,//if has backtest module 105 | "tradeListLen": 1,//watch pair length 106 | "startCapital": 1000,//start capital 107 | "currentCapital": 800.10957177,//current useful capital 108 | "tradeNum": 12,//traded pair number 109 | "dynamicUsdtProfit": -0.0290142,//unrealized profit 110 | "dynamicProfit": -0.0000290142,//unrealized profit rate 111 | "usdtProfit": -0.19980051799999998,//USDT profit 112 | "profit": -0.000199800518,//profit rate 113 | "exchange": "mexc",//bot exchange 114 | "startTime": 1681111671975,//bot start time 115 | "timeZoneOffset": -480,//server timezone offset 116 | "status": "work",//current bot status 117 | "win": 4, 118 | "lost": 1, 119 | "winLostRate": 0.8, 120 | "totalCapital":999.32 //current capital,include profit and unrealized profit 121 | } 122 | } 123 | ``` 124 | 125 | ### - refresh 126 | 127 | Get current bot update data 128 | 129 | > The server regularly broadcasts real-time data to the client 130 | > Broadcast data to the client when a specific event occurs, such as new order is created 131 | 132 | #### Request 133 | 134 | ```javascript 135 | { 136 | "action": "refresh", 137 | "apiKey": "YOUR API KEY" 138 | } 139 | ``` 140 | 141 | #### Response 142 | 143 | ```javascript 144 | { 145 | "action": "refresh", 146 | "data": { 147 | "symbols": [ //all pairs 148 | { 149 | "product_id": "ETH-USDT", //pair name 150 | "price": 1858.08, //pair price 151 | "normalized": "mexc.ETH-USDT",//pair full name 152 | "min_size": "0.00001",//pair min size 153 | "asset": "ETH", 154 | "currency": "USDT", 155 | "assetCaptial": 0, 156 | "leverage": 10,// future leverage 157 | "isolated": false,//future mode 158 | "usdtProfit": 0,//USDT profit 159 | "dynamicProfit": 0,//unrealized USDT profit 160 | "dynamicUsdtProfit": 0,//unrealized USDT profit rate 161 | "profit": 0,//USDT USDT profit rate 162 | "signal": null,//signal include 'buying','selling','bought','sold' 163 | "win": 0,//win count 164 | "lost": 0,//lost count 165 | "winLostRate": 0,//win rate 166 | "trades": [{// pair order list 167 | "order_id": 1001, //order ID 168 | "time": 1681111866476,//order time 169 | "execution_time": 5001,//order execution time 170 | "slippage": 0,//order slippage 171 | "type": "buy",//order position type, buy or sell 172 | "size": "0.10757",//order size 173 | "fee": 0.19980051799999998,//order fee usdt 174 | "price": "1857.40", //order price 175 | "order_type": "maker",//order type 'maker' or 'taker' 176 | "action": "BollingerBands_buy_long",//order buy or send strategy type 177 | "profit": -0.0009999999999999998, //order porfit 178 | "usdtProfit": -0.19980051799999998,//order profit rate 179 | "position_side": "long",//order position side 'long' or 'short' 180 | }, 181 | ... 182 | ], 183 | "lastTradeTime": 0,//last trade time 184 | "klines": [//Kline data 185 | { 186 | "period_id": "m28018427", 187 | "time": 1681105620000, 188 | "size": "1m", 189 | "close_time": 1681105679999, 190 | "open": 1863.3, 191 | "high": 1863.38, 192 | "low": 1862.22, 193 | "close": 1862.22, 194 | "volume": 45.16688, 195 | "strategy": { //kline data for strategy 196 | "BollingerBands_buyCrossCount": 0,//bb buy point count in this period 197 | "BollingerBands_sellCrossCount": 1,//bb sell point count in this period 198 | "BollingerBands_buy": false,//if bb has buy point 199 | "BollingerBands_sell": false//if bb has sell point 200 | "middle": 1856.3892857142853,//bb middle 201 | "upper": 1858.8566899522384,//bb uper 202 | "lower": 1853.9218814763321,//bb lower 203 | "pw": 0.26582832134842305,//bb pw 204 | } 205 | } 206 | ... 207 | ] 208 | }, 209 | ... 210 | ], 211 | "status": { //bot status 212 | "tradeListLen": 1,//watch pair length 213 | "startCapital": 1000,//start capital 214 | "currentCapital": 800.10957177,//current useful capital 215 | "tradeNum": 12,//traded pair number 216 | "dynamicUsdtProfit": -0.0290142,//unrealized profit 217 | "dynamicProfit": -0.0000290142,//unrealized profit rate 218 | "usdtProfit": -0.19980051799999998,//USDT profit 219 | "profit": -0.000199800518,//profit rate 220 | "exchange": "mexc",//bot exchange 221 | "startTime": 1681111671975,//bot start time 222 | "timeZoneOffset": -480,//server timezone offset 223 | "status": "work",//current bot status 224 | "win": 4, 225 | "lost": 1, 226 | "winLostRate": 0.8, 227 | "totalCapital":999.32 //current capital,include profit and unrealized profit 228 | } 229 | } 230 | } 231 | ``` 232 | -------------------------------------------------------------------------------- /docs/zh/README.md: -------------------------------------------------------------------------------- 1 | # 用户文档 2 | 3 | **简介:** 4 | 5 | - [关于灵丹](panacea.md) 6 | - [开发者](developer.md) 7 | - [常见问题](faq.md) 8 | 9 | **API:** 10 | 11 | - [状态](status.md) 12 | - [操作](operation.md) 13 | - [配置](config.md) 14 | - [策略](strategy.md) 15 | - [行情](market.md) 16 | -------------------------------------------------------------------------------- /docs/zh/config.md: -------------------------------------------------------------------------------- 1 | # 配置API 2 | 3 | 配置API为客户端的配置模块提供必要数据,通过配置模块,您在服务器的所有配置均可通过客户端进行实时更新。目前包括以下API 4 | 5 | - init 获得配置设置与配置值 6 | - updateConfig 更新配置 7 | - updateSymbolFuture 更新交易对配置 8 | 9 | ## 必需实现 10 | 11 | > **可选** 12 | > 如果不实现此API,客户端将不会有配置模块. 13 | > 如果未实现此API,在状态API请将机器人状态的`init`中请将`hasConfig`设置为`false` 14 | 15 | ## 更新流程 16 | 17 | - 在`init`事件中传递配置设置与配置值 18 | - 通过配置设置在客户端生成相关联的UI界面 19 | - 通过UI界面修改配置并通过`updateConfig`更新服务器端值 20 | 21 | ## API列表 22 | 23 | ### - init 24 | 25 | 当使用配置模块时,配置设置与配置参数将通过`init`传递至客户端 26 | 27 | #### 请求参数 28 | 29 | > 用户初次连接机器人成功时,服务器将主动推送。 30 | > 用户设备重新连接(比如浏览器移动设备resume事件)也会主动推送 31 | 32 | ```javascript 33 | { 34 | "action": "init", 35 | "apiKey":"YOUR API KEY" 36 | } 37 | ``` 38 | 39 | #### 返回结果 40 | 41 | ```javascript 42 | { 43 | "options": { //机器人配置 ,用户提交config并在此处传入实时值,详见 config组 44 | "strategy": "BollingerBands", 45 | "period": "10m", 46 | "debug": false 47 | ... 48 | }, 49 | "config": { //机器人配置设置,结构为分组,小分组,条目 ,可查看XCoin相关配置 50 | "bot": [//机器人相关配置分组,以下例子使用了不同种类的 51 | { 52 | "name": "strategy",//配置名称 比如策略名称 53 | "type": "string",//字符类型 54 | "value": "BollingerBands"//配置值 55 | }, 56 | { 57 | "name": "period",//配置名称,比如周期选择 58 | "type": "array",//列表类型 59 | "list": [//列表值 60 | "1m", 61 | "3m", 62 | "5m" 63 | ], 64 | "value": "5m" 65 | }, 66 | { 67 | "name": "debug",//配置名称,比如是否调试 68 | "type": "bool",//布尔类型 69 | "value": false 70 | }, 71 | { 72 | "name": "other",//分组名称,比如其它 73 | "type": "group"//分组类型,分组类型下的所有设置将在分组中显示 74 | }, 75 | { 76 | "name": "poll_scan_time",//配置名称,比如轮循时间 77 | "type": "number",//数值类型 78 | "step": [//通过step设置 79 | 1000,//最小值 80 | 60000,//最大值 81 | 500//步长 82 | ], 83 | "value": 3000, 84 | "des": true//存在描述 85 | }, 86 | { 87 | "name": "black_list",//配置名称,比如黑名单列 88 | "type": "textarea",//长字符串类型 89 | "value": 'binance.BTC-USDT,binance.AAB-USDt', //配置值 90 | "des": true//存在描述 91 | }, 92 | ... 93 | ], 94 | "exchange": [], //交易所相关, 95 | "order": [], //订单相关, 96 | "sellPoint": [], //止赢止损相关相关, 97 | "watch": [], //监控池相关 98 | "paper":[],//模拟交易相关 99 | } 100 | } 101 | ``` 102 | 103 | ### - updateConfig 104 | 105 | 更新机器人参数 106 | 107 | #### 请求参数 108 | 109 | ```javascript 110 | { 111 | "action": "updateConfig", 112 | "restart": true, //本次更新需要重启机器人 113 | "data": { 114 | "period": "3m", //更新的参数 115 | "buy_pct":30 //更新的参数 116 | }, 117 | "apiKey": "YOUR API KEY" 118 | } 119 | ``` 120 | 121 | #### 返回结果 122 | 123 | ```javascript 124 | { 125 | "action": "updateConfig", 126 | "data":Object, //返回全部配置参数 方便更 127 | "toast": "trade.updateConfigOk" 128 | } 129 | ``` 130 | 131 | ### - updateSymbolFuture 132 | 133 | 更新指定交易对的期货参数,目前支持杠杆倍数与全仓逐仓模式的更新 134 | 135 | #### 请求参数 136 | 137 | ```javascript 138 | { 139 | "action": "updateSymbolFuture", 140 | "symbol":"BTC-USDT", //交易对 141 | "data":{ 142 | "type":"leverage",//marginMode or leverage 143 | "value":10 //type为marginMode时,值为 cross或isolated 144 | }, 145 | "apiKey": "YOUR API KEY" 146 | } 147 | ``` 148 | 149 | #### 返回结果 150 | 151 | ```javascript 152 | { 153 | "action": "updateSymbolFuture", 154 | "toast": "trade.updateSymbolFutureOk" 155 | } 156 | ``` 157 | 158 | > 一个示例的配置设置文件 159 | 160 | ````json 161 | { 162 | "bot": [ 163 | { 164 | "name": "strategy", 165 | "type": "string", 166 | "value": "rain_sar" 167 | }, 168 | { 169 | "name": "period", 170 | "type": "array", 171 | "list": [ 172 | "1m", 173 | "3m", 174 | "5m", 175 | "15m", 176 | "30m", 177 | "1h", 178 | "2h", 179 | "4h", 180 | "8h", 181 | "12h", 182 | "1d", 183 | "3d", 184 | "1w" 185 | ], 186 | "value": "30m" 187 | }, 188 | { 189 | "name": "mode", 190 | "type": "array", 191 | "list": [ 192 | "live", 193 | "paper" 194 | ], 195 | "value": "live" 196 | }, 197 | { 198 | "name": "trade_type", 199 | "type": "array", 200 | "list": [ 201 | "auto", 202 | "autoBuy", 203 | "autoSell", 204 | "manual" 205 | ], 206 | "value": "live" 207 | }, 208 | { 209 | "name": "debug", 210 | "type": "bool", 211 | "value": false 212 | }, 213 | { 214 | "name": "other", 215 | "type": "group" 216 | }, 217 | { 218 | "name": "poll_scan_time", 219 | "type": "number", 220 | "step": [ 221 | 1000, 222 | 60000, 223 | 500 224 | ], 225 | "value": 3000, 226 | "des": true 227 | }, 228 | { 229 | "name": "poll_broadcast_time", 230 | "type": "number", 231 | "step": [ 232 | 3000, 233 | 60000, 234 | 1000 235 | ], 236 | "value": 5000, 237 | "des": true 238 | }, 239 | { 240 | "name": "save_bot_time", 241 | "type": "number", 242 | "step": [ 243 | 6000, 244 | 6000000, 245 | 6000 246 | ], 247 | "value": 600000, 248 | "des": true 249 | }, 250 | { 251 | "name": "min_periods", 252 | "type": "number", 253 | "step": [ 254 | 18, 255 | 500, 256 | 1 257 | ], 258 | "value": 32 259 | }, 260 | { 261 | "name": "keep_lookback_periods", 262 | "type": "number", 263 | "step": [ 264 | 50, 265 | 50000, 266 | 10 267 | ], 268 | "value": 500 269 | }, 270 | { 271 | "name": "price_format", 272 | "type": "string", 273 | "value": "0.00000000" 274 | }, 275 | { 276 | "name": "same_period_multi_buy", 277 | "type": "bool", 278 | "value": false 279 | }, 280 | { 281 | "name": "run_for", 282 | "type": "number", 283 | "step": [ 284 | 0, 285 | 1000, 286 | 1 287 | ], 288 | "value": 0, 289 | "des": true 290 | } 291 | ], 292 | "exchange": [ 293 | { 294 | "name": "exchange", 295 | "type": "array", 296 | "list": [ 297 | "binanceusdm", 298 | "binance", 299 | "mexc" 300 | ], 301 | "value": "binanceusdm" 302 | }, 303 | { 304 | "name": "takerFee", 305 | "type": "number", 306 | "step": [ 307 | 0.001, 308 | 0.5, 309 | 0.001 310 | ], 311 | "value": 0.1 312 | }, 313 | { 314 | "name": "makerFee", 315 | "type": "number", 316 | "step": [ 317 | 0.001, 318 | 0.5, 319 | 0.001 320 | ], 321 | "value": 0.1 322 | }, 323 | { 324 | "name": "future", 325 | "type": "group" 326 | }, 327 | { 328 | "name": "future", 329 | "type": "bool", 330 | "value": false, 331 | "readonly": true 332 | }, 333 | { 334 | "name": "market", 335 | "type": "array", 336 | "list": [ 337 | "only_long", 338 | "only_short", 339 | "both" 340 | ], 341 | "value": "only_long" 342 | }, 343 | { 344 | "name": "leverage", 345 | "type": "number", 346 | "step": [ 347 | 2, 348 | 125, 349 | 1 350 | ], 351 | "value": 10 352 | }, 353 | { 354 | "name": "marginMode", 355 | "type": "array", 356 | "list": [ 357 | "cross", 358 | "isolated" 359 | ], 360 | "value": "isolated" 361 | }, 362 | { 363 | "name": "short_buy_pct", 364 | "type": "number", 365 | "step": [ 366 | 0, 367 | 100, 368 | 1 369 | ], 370 | "value": 20 371 | }, 372 | { 373 | "name": "buy_position_side_when_sell", 374 | "type": "bool", 375 | "value": false 376 | } 377 | ], 378 | "order": [ 379 | { 380 | "name": "order_type", 381 | "type": "array", 382 | "list": [ 383 | "maker", 384 | "taker" 385 | ], 386 | "value": "maker" 387 | }, 388 | { 389 | "name": "max_slippage_pct", 390 | "type": "number", 391 | "step": [ 392 | 0.1, 393 | 2, 394 | 0.1 395 | ], 396 | "value": 0.5, 397 | "group": "core" 398 | }, 399 | { 400 | "name": "buy", 401 | "type": "group" 402 | }, 403 | { 404 | "name": "buy_pct", 405 | "type": "number", 406 | "step": [ 407 | 0, 408 | 100, 409 | 1 410 | ], 411 | "value": 20 412 | }, 413 | { 414 | "name": "min_buy_size", 415 | "type": "number", 416 | "step": [ 417 | 0, 418 | 100, 419 | 1 420 | ], 421 | "value": 10 422 | }, 423 | { 424 | "name": "max_buy_size", 425 | "type": "number", 426 | "step": [ 427 | 0, 428 | 10000, 429 | 100 430 | ], 431 | "value": 0 432 | }, 433 | { 434 | "name": "sell", 435 | "type": "group" 436 | }, 437 | { 438 | "name": "sell_pct", 439 | "type": "number", 440 | "step": [ 441 | 0, 442 | 100, 443 | 1 444 | ], 445 | "value": 100, 446 | "group": "sell" 447 | }, 448 | { 449 | "name": "other", 450 | "type": "group" 451 | }, 452 | { 453 | "name": "order_adjust_time", 454 | "type": "number", 455 | "step": [ 456 | 1000, 457 | 1000, 458 | 1000 459 | ], 460 | "value": 5000, 461 | "group": "other" 462 | }, 463 | { 464 | "name": "max_sell_loss_pct", 465 | "type": "number", 466 | "step": [ 467 | 0, 468 | 5, 469 | 0.5 470 | ], 471 | "value": 1, 472 | "group": "other" 473 | }, 474 | { 475 | "name": "max_buy_loss_pct", 476 | "type": "number", 477 | "step": [ 478 | 0, 479 | 5, 480 | 0.5 481 | ], 482 | "value": 1, 483 | "group": "other" 484 | }, 485 | { 486 | "name": "order_poll_time", 487 | "type": "number", 488 | "step": [ 489 | 1000, 490 | 60000, 491 | 1000 492 | ], 493 | "value": 5000, 494 | "group": "other" 495 | }, 496 | { 497 | "name": "wait_for_settlement", 498 | "type": "number", 499 | "step": [ 500 | 1000, 501 | 60000, 502 | 1000 503 | ], 504 | "value": 5000, 505 | "group": "other", 506 | "des": true 507 | }, 508 | { 509 | "name": "markdown_buy_pct", 510 | "type": "number", 511 | "step": [ 512 | 0, 513 | 5, 514 | 0.1 515 | ], 516 | "value": 0, 517 | "group": "other" 518 | }, 519 | { 520 | "name": "markup_sell_pct", 521 | "type": "number", 522 | "step": [ 523 | 0, 524 | 5, 525 | 0.1 526 | ], 527 | "value": 0, 528 | "group": "other" 529 | }, 530 | { 531 | "name": "post_only", 532 | "type": "bool", 533 | "value": false, 534 | "group": "other" 535 | }, 536 | { 537 | "name": "use_fee_asset", 538 | "type": "bool", 539 | "value": false, 540 | "group": "other" 541 | }, 542 | { 543 | "name": "avg_slippage_pct", 544 | "type": "number", 545 | "value": 0.045, 546 | "step": [ 547 | 0, 548 | 0.1, 549 | 0.005 550 | ], 551 | "group": "other" 552 | }, 553 | { 554 | "name": "quarentine_time", 555 | "type": "number", 556 | "step": [ 557 | 0, 558 | 100000, 559 | 1000 560 | ], 561 | "value": 0, 562 | "group": "other" 563 | } 564 | ], 565 | "sellPoint": [ 566 | { 567 | "name": "sell_stop_pct", 568 | "type": "number", 569 | "step": [ 570 | 0, 571 | 30, 572 | 0.1 573 | ], 574 | "value": 5 575 | }, 576 | { 577 | "name": "profitStop", 578 | "type": "group" 579 | }, 580 | { 581 | "name": "profit_stop_enable", 582 | "type": "bool", 583 | "value": true 584 | }, 585 | { 586 | "name": "profit_stop_percent", 587 | "type": "number", 588 | "step": [ 589 | 0, 590 | 100, 591 | 1 592 | ], 593 | "value": 50 594 | }, 595 | { 596 | "name": "profit_stop_first_rate", 597 | "type": "number", 598 | "step": [ 599 | 0, 600 | 500, 601 | 1 602 | ], 603 | "value": 10 604 | }, 605 | { 606 | "name": "profit_stop_first_percent", 607 | "type": "number", 608 | "step": [ 609 | 0, 610 | 100, 611 | 1 612 | ], 613 | "value": 30 614 | }, 615 | { 616 | "name": "profit_stop_second_rate", 617 | "type": "number", 618 | "step": [ 619 | 0, 620 | 500, 621 | 1 622 | ], 623 | "value": 20 624 | }, 625 | { 626 | "name": "profit_stop_second_percent", 627 | "type": "number", 628 | "step": [ 629 | 0, 630 | 100, 631 | 1 632 | ], 633 | "value": 40 634 | }, 635 | { 636 | "name": "profit_stop_third_rate", 637 | "type": "number", 638 | "step": [ 639 | 0, 640 | 500, 641 | 1 642 | ], 643 | "value": 50 644 | }, 645 | { 646 | "name": "profit_stop_third_percent", 647 | "type": "number", 648 | "step": [ 649 | 0, 650 | 100, 651 | 1 652 | ], 653 | "value": 50 654 | }, 655 | { 656 | "name": "profit_stop_max_rate", 657 | "type": "number", 658 | "step": [ 659 | 0, 660 | 500, 661 | 1 662 | ], 663 | "value": 100 664 | }, 665 | { 666 | "name": "profit_stop_max_percent", 667 | "type": "number", 668 | "step": [ 669 | 0, 670 | 100, 671 | 1 672 | ], 673 | "value": 70 674 | }, 675 | { 676 | "name": "profitSell", 677 | "type": "group" 678 | }, 679 | { 680 | "name": "profit_win_enable", 681 | "type": "bool", 682 | "value": true 683 | }, 684 | { 685 | "name": "profit_win_first_rate", 686 | "type": "number", 687 | "step": [ 688 | 0, 689 | 500, 690 | 1 691 | ], 692 | "value": 25 693 | }, 694 | { 695 | "name": "profit_win_first_percent", 696 | "type": "number", 697 | "step": [ 698 | 0, 699 | 100, 700 | 1 701 | ], 702 | "value": 50 703 | }, 704 | { 705 | "name": "profit_win_second_rate", 706 | "type": "number", 707 | "step": [ 708 | 0, 709 | 500, 710 | 1 711 | ], 712 | "value": 50 713 | }, 714 | { 715 | "name": "profit_win_second_percent", 716 | "type": "number", 717 | "step": [ 718 | 0, 719 | 100, 720 | 1 721 | ], 722 | "value": 50 723 | }, 724 | { 725 | "name": "profit_win_third_rate", 726 | "type": "number", 727 | "step": [ 728 | 0, 729 | 500, 730 | 1 731 | ], 732 | "value": 100 733 | }, 734 | { 735 | "name": "profit_win_third_percent", 736 | "type": "number", 737 | "step": [ 738 | 0, 739 | 100, 740 | 1 741 | ], 742 | "value": 50 743 | }, 744 | { 745 | "name": "profit_win_max_rate", 746 | "type": "number", 747 | "step": [ 748 | 0, 749 | 500, 750 | 1 751 | ], 752 | "value": 200 753 | }, 754 | { 755 | "name": "profit_win_max_percent", 756 | "type": "number", 757 | "step": [ 758 | 0, 759 | 100, 760 | 1 761 | ], 762 | "value": 50 763 | } 764 | ], 765 | "watch": [ 766 | { 767 | "name": "max_watch_size", 768 | "type": "number", 769 | "step": [ 770 | 0, 771 | 30, 772 | 5 773 | ], 774 | "value": 10 775 | }, 776 | { 777 | "name": "watch_symbols", 778 | "type": "textarea", 779 | "value": "", 780 | "placeholder": true 781 | }, 782 | { 783 | "name": "watchInit", 784 | "type": "group" 785 | }, 786 | { 787 | "name": "watch_include_bought", 788 | "type": "bool", 789 | "value": true 790 | }, 791 | { 792 | "name": "watch_with_black_list", 793 | "type": "bool", 794 | "value": true 795 | }, 796 | { 797 | "name": "black_list", 798 | "type": "textarea", 799 | "value": "", 800 | "placeholder": true 801 | } 802 | ], 803 | "paper": [ 804 | { 805 | "name": "currency_capital", 806 | "type": "number", 807 | "step": [ 808 | 0, 809 | 10000, 810 | 1000 811 | ], 812 | "value": 1000 813 | }, 814 | { 815 | "name": "asset_capital", 816 | "type": "number", 817 | "step": [ 818 | 0, 819 | 10000, 820 | 1000 821 | ], 822 | "value": 0 823 | } 824 | ] 825 | } 826 | ```` 827 | -------------------------------------------------------------------------------- /docs/zh/developer.md: -------------------------------------------------------------------------------- 1 | # 开发者 2 | 3 | 灵丹为交易机器人提供一个统一的易管理的实时反映交易状态的界面,您可以通过开发扩展来适应您自己的机器人,我们也欢迎您添加基于Freqtrade,zenbot等的功能扩展 4 | 5 | ## 扩展开发流程 6 | 7 | 1. 了解灵丹API并决定您需要适配哪些API 8 | 2. 在您的机器人代码里添加基于灵丹的扩展 9 | 3. 下载灵丹应用程序 [下载灵丹](https://www.ciiat.com/download),添加您的交易机器人进行测试 10 | 4. 您也可以直接通过 [Web版灵丹](https://www.ciiat.com/app/www) 直接添加您的交易机器人进行测试 11 | 5. 下载灵丹API代码,将您的相关代码放置在 `extensions` 目录 12 | 6. 提交一个PR,我们会尽快进行合并 13 | 14 | ## 注意事项 15 | 16 | - 添加代码时需要在根目录添加README.md文件以帮助用户了解使用扩展的细节 17 | - 所有扩展均需要遵循 `MIT` 授权 18 | - 您可以随时通过运行 [XCoin](https://github.com/rianfu/xcoin) 来对比扩展传递内容. 19 | -------------------------------------------------------------------------------- /docs/zh/faq.md: -------------------------------------------------------------------------------- 1 | # 常见问题 2 | 3 | 以下是一些经常被问到的问题以及来自社区的回答。 4 | 5 | 如果您有此处未回答的问题,请随时在社区中提问,并建议将其放在此处。 6 | 7 | 谢谢! 8 | 9 | ## 问题 10 | 11 | ### [开发](#开发) 12 | 13 | ## 答案 14 | 15 | ### 开发 16 | -------------------------------------------------------------------------------- /docs/zh/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: home 3 | 4 | hero: 5 | name: 灵丹 6 | text: 交易机器人实时状态管理 7 | tagline: 随时随地管理您的交易机器人。 8 | image: 9 | src: /images/web_top.png 10 | alt: 灵丹 11 | 12 | actions: 13 | - theme: brand 14 | text: 快速开始 15 | link: /zh/panacea 16 | - theme: sponsor 17 | text: 演示 18 | link: https://www.ciiat.com/app/www 19 | - theme: sponsor 20 | text: 下载 21 | link: https://www.ciiat.com/download 22 | - theme: alt 23 | text: 在 GitHub 上查看 24 | link: https://github.com/markmind/panacea-api 25 | 26 | features: 27 | - title: 提供统一API 28 | details: 支持多种开源交易机器人或商业闭源机器人。 29 | - title: 支持所有客户端 30 | details: 任意时间,任意地点通过桌面或移动设备管理您的交易。 31 | - title: 多机器人管理 32 | details: 支持管理多个机器人,一键切换。 33 | - title: 支持实时交易 34 | details: 支持多空操作,支持买卖点显示。 35 | - title: 支持配置参数实时修改 36 | details: 支持在运行时更改参数,支持远程启停以应用参数。 37 | - title: 支持策略参数实时修改 38 | details: 支持在运行时更改策略或调整策略参数,支持远程启停以策略。 39 | --- -------------------------------------------------------------------------------- /docs/zh/market.md: -------------------------------------------------------------------------------- 1 | # 市场API 2 | 3 | 市场API为客户端的市场模块提供必要数据,目前包括以下API 4 | 5 | - getProducts 获得产品列表 6 | - getTickers 获得产品价格 7 | - getKlines 获得特定交易对的K线 8 | - getPickerNormal 获得热门产品 9 | 10 | ## 必需实现 11 | 12 | > **可选** 13 | > 如果不实现此API,客户端将不会有市场模块 14 | > 如果未实现此API,在状态API请将机器人状态的`init`中请将`hasMarket`设置为`false` 15 | 16 | ## API列表 17 | 18 | ### - getProducts 19 | 20 | 获取当前机器人所在交易所的所有产品 21 | 22 | #### 请求参数 23 | 24 | ```javascript 25 | { 26 | "action": "getProducts", 27 | "apiKey":"YOUR API KEY" 28 | } 29 | ``` 30 | 31 | #### 返回结果 32 | 33 | ```javascript 34 | { 35 | "action": "getProducts", 36 | "data":[{ 37 | "id": "1INCH_USDT", //交易对 38 | "asset": "1INCH",//asset 39 | "currency": "USDT",//currency 40 | "active": true, 41 | "min_size": "0.01",//最小交易对单位 42 | "increment": "0.0001",//最小价格单位 43 | "asset_increment": "0.01",//最小交易对增量 44 | "label": "1INCH/USDT", 45 | "exchagne_id": "mexc", 46 | "product_id": "1INCH-USDT", 47 | "normalized": "mexc.1INCH-USDT" 48 | }, 49 | ... 50 | ] 51 | } 52 | ``` 53 | 54 | ### - getTickers 55 | 56 | 获取当前机器人所在交易所的所有或指定产品的实时价格, 57 | 58 | > 不传symbols参数时将返回所有产品的价格 59 | 60 | #### 请求参数 61 | 62 | ```javascript 63 | { 64 | "action": "getTickers", 65 | "data": { 66 | "symbols": [ 67 | { 68 | "product_id": "1INCH-USDT" //交易对名称 69 | }, 70 | ... 71 | ] 72 | }, 73 | "apiKey": "YOUR API KEY" 74 | } 75 | ``` 76 | 77 | #### 返回结果 78 | 79 | ```javascript 80 | { 81 | "action": "getTickers", 82 | "data": [ 83 |     { 84 |     "symbol": "GDO/USDT",//交易对名称 85 |     "price": 8.98e-8, //当前价格 86 |     "percentage": 1 //24hr价格变化率 87 |     } 88 |     ... 89 | ] 90 | } 91 | ``` 92 | 93 | ### - getPickerNormal 94 | 95 | 获取当前机器人所在交易所的热门产品 96 | 97 | > 目前支持的热门产品为指定周期内的最大涨幅,最大,最小振幅,连续上涨与阳线最多5个部分 98 | 99 | #### 请求参数 100 | 101 | ```javascript 102 | { 103 | "action": "getPickerNormal", 104 | "data": { 105 | "period": "1d", //K线周期 106 | "limit": 10,// 返回结果数量 107 | "number": 8 // K线长度 108 | }, 109 | "apiKey": "YOUR API KEY" 110 | } 111 | ``` 112 | 113 | #### 返回结果 114 | 115 | ```javascript 116 | { 117 | "action": "getPickerNormal", 118 | "data": { 119 | "maxSum": [//最大振幅 120 | { 121 | "index": 1, //排名 122 | "product_id": "ARB-USDT", 123 | "price": 1.3181, 124 | "extra": "12400.37%", //总振幅 125 | "klines": [ 126 | { 127 | "time": 1679529600000, 128 | "close": 1.3181 129 | } 130 | ... 131 | ] 132 | } 133 | ... 134 | ], 135 | "minSum": [//最小振幅 136 | { 137 | "index": 1,//排名 138 | "product_id": "BUSD-USDT", 139 | "price": 0.9982, 140 | "extra": "2.04%", //总振幅 141 | "klines": [ 142 | { 143 | "time": 1678752000000, 144 | "close": 0.9965 145 | }, 146 | ... 147 | ] 148 | }, 149 | ... 150 | ], 151 | "fastUp": [//最大涨幅 152 | { 153 | "index": 1,//排名 154 | "product_id": "ID-USDT", 155 | "price": 0.5285, 156 | "extra": "2014.00%",//总涨幅 157 | "klines": [ 158 | { 159 | "time": 1679443200000, 160 | "close": 0.40696 161 | }, 162 | ... 163 | ] 164 | }, 165 | ... 166 | ], 167 | "moreUp": [//最多阳线 168 | { 169 | "index": 1,// 排名 170 | "product_id": "LOOP-USDT", 171 | "price": 0.12923, 172 | "extra": "9/10",// 阳线数量 173 | "klines": [ 174 | { 175 | "time": 1679529600000, 176 | "close": 0.12923 177 | }, 178 | ... 179 | ] 180 | }, 181 | ... 182 | ], 183 | "continueUp": [//连续涨 184 | { 185 | "index": 1, //排名 186 | "product_id": "LOOP-USDT", 187 | "price": 0.12923, 188 | "extra": 9, //连续涨数量 189 | "klines": [ 190 | { 191 | "time": 1678752000000, 192 | "close": 0.03596 193 | }, 194 | ... 195 | ], 196 | ... 197 | } 198 | ] 199 | } 200 | } 201 | ``` 202 | 203 | ### getKlines 204 | 205 | 获取当前机器人所在交易所的某一产品的K线图 206 | 207 | #### 请求参数 208 | 209 | ```javascript 210 | { 211 | "action": "getKlines", 212 | "symbol": "ALGO-USDT", //交易对名称 213 | "data": { 214 | "product_id": "ALGO-USDT", 215 | "limit": 60, //K线长度 216 | "period": "30m" //K线周期 217 | }, 218 | "apiKey": "YOUR API KEY" 219 | } 220 | ``` 221 | 222 | #### 返回结果 223 | 224 | ```javascript 225 | { 226 | "action": "getKlines", 227 | "data": { 228 | "period": "30m", //K线周期 229 | "klines": [ 230 | { 231 | "period_id": "30m933888",//kline id 232 | "time": 1680768000,//K线开始时间 233 | "size": "30m",//K线周期 234 | "close_time": 1681000199999,//k线结束时间 235 | "open": 0.216, 236 | "high": 0.2169, 237 | "low": 0.2157, 238 | "close": 0.2169, 239 | "volume": 12943.41 240 | } 241 | ... 242 | ] 243 | } 244 | } 245 | ``` 246 | -------------------------------------------------------------------------------- /docs/zh/operation.md: -------------------------------------------------------------------------------- 1 | # 操作API 2 | 3 | 操作API为客户端的机器人模块提供与服务器的交互,根据功能的不同可分为几个类型 4 | 5 | - 对监控池的交易对的操作 6 | - 添加新交易对 7 | - 删除交易对 8 | - 清空交易池 9 | - 特定交易对的交易 10 | - 买 11 | - 卖 12 | - 清仓 13 | 14 | ## 必需实现 15 | 16 | > **必选** 17 | 18 | ## API列表 19 | 20 | ### - addSymbol 21 | 22 | 将新的交易对添加至交易池 23 | 24 | #### 请求参数 25 | 26 | ```javascript 27 | { 28 | "action": "addSymbol", 29 | "symbols": [ 30 | "mexc.ACM-USDT" //添加的交易对数组 31 | ], 32 | "data": {}, 33 | "apiKYOUR API KEYJYOyKq" 34 | } 35 | ``` 36 | 37 | #### 返回结果 38 | 39 | ```javascript 40 | { 41 | "action": "addSymbol", 42 | "toast": "trade.addSymbolOk",//成功后消息提醒信息 43 | "data": { 44 | "success": true 45 | } 46 | } 47 | ``` 48 | 49 | ### - removeSymbol 50 | 51 | 将指定交晚对从监控池移除, 52 | 53 | #### 请求参数 54 | 55 | ```javascript 56 | { 57 | "action": "removeSymbol", 58 | "symbol": "mexc.ETH-USDT", //清除交易对名称 59 | "apiKey": "YOUR API KEY" 60 | } 61 | ``` 62 | 63 | #### 返回结果 64 | 65 | ```javascript 66 | { 67 | "action": "removeSymbol", 68 | "toast": "trade.removeSymbolOk", 69 | "data": { 70 | "success": true 71 | } 72 | } 73 | ``` 74 | 75 | ### - removeAllSymbol 76 | 77 | 清空交易池中的交易对 78 | 79 | #### 请求参数 80 | 81 | ```javascript 82 | { 83 | "action": "removeAllSymbol", 84 | "apiKey": "YOUR API KEY" 85 | } 86 | ``` 87 | 88 | #### 返回结果 89 | 90 | ```javascript 91 | { 92 | "action": "removeAllSymbol", 93 | "toast": "trade.removeAllSymbolOk" 94 | } 95 | ``` 96 | 97 | ### buy 98 | 99 | 购买指定交易对 100 | 101 | #### 请求参数 102 | 103 | ```javascript 104 | { 105 | "action": "buy", 106 | "symbol": "BTC-USDT", 107 | "data": { 108 | "position_side": "LONG", //LONG 买多 OR SHORT 买空 109 | "size":20//买入数量 110 | }, 111 | "apiKey": "YOUR API KEY" 112 | } 113 | ``` 114 | 115 | #### 返回结果 116 | 117 | ```javascript 118 | { 119 | "action": "buy", 120 | "toast": "trade.buyOk" //返回消息提醒 121 | } 122 | ``` 123 | 124 | ### -Sell 125 | 126 | 卖出指定交易对 127 | 128 | #### 请求参数 129 | 130 | ```javascript 131 | { 132 | "action": "sell", 133 | "symbol": "BTC-USDT", 134 | "data": { 135 | "position_side": "LONG", //LONG 卖多 OR SHORT 卖空 136 | "size":20//卖出数量 137 | }, 138 | "apiKey": "YOUR API KEY" 139 | } 140 | ``` 141 | 142 | #### 返回结果 143 | 144 | ```javascript 145 | { 146 | "action": "sell", 147 | "toast": "trade.sellOk" //返回消息提醒 148 | } 149 | ``` 150 | 151 | ### - sellAll 152 | 153 | 卖出所有交易对 154 | 155 | #### 请求参数 156 | 157 | ```javascript 158 | { 159 | "action": "sellAll", 160 | "apiKey": "YOUR API KEY" 161 | } 162 | ``` 163 | 164 | #### 返回结果 165 | 166 | ```javascript 167 | { 168 | "action": "sellAll", 169 | "toast": "trade.sellAllOk" //返回消息提醒 170 | } 171 | ``` 172 | -------------------------------------------------------------------------------- /docs/zh/panacea.md: -------------------------------------------------------------------------------- 1 | # 关于灵丹 2 | 3 | 灵丹通过一个简易的方法来扩展您的交易机器人的功能,让您可以通过桌面或移动设备在任何时间、任何地点都能操控与观察您的机器人,通过对状态、交互、配置、策略等的合理配置,您能更快速更合理地找出理想的交易方式,极大地减小了量化交易的风险,提升了交易的赢利能力。 4 | 5 | 在将你的交易机器人适配至灵丹之前,您需要了解一些我们的工作方式。 6 | 7 | ## 屏幕截图 8 | 9 | ### 桌面版 10 | 11 | 包括 Windows,Osx and Linux 客户端 12 | 13 | ![桌面版](/images/desktop_cn.jpg) 14 | 15 | ### 移动版 16 | 17 | 包括 Android and Ios 客户端 18 | 19 | ![移动版](/images/screenshot_mobile_zh.jpg) 20 | 21 | ## 页面架构 22 | 23 | 根据您实现API的内容,灵丹将显示不同的页面内容 24 | 25 | >状态与操作API是必需实现的灵丹的核心功能 26 | >如果您未实现配置功能,灵丹配置管理模块将不会被启用 27 | 28 | - 机器人 29 | - 机器人管理 30 | - 配置管理 31 | - 策略管理 32 | - 监控列表 33 | - 交易对交易 34 | - 交易对历史成交 35 | - 市场 36 | - 全部交易对 37 | - 交易队详情 38 | - 获得热门产品 39 | 40 | ## API支持 41 | 42 | - 机器人实时状态初始化与更新 `必选` 43 | - 机器人操作 `必选` 44 | - 机器人配置 `可选` 45 | - 机器人策略 `可选` 46 | - 机器人所在交易市场行情 `可选` 47 | -------------------------------------------------------------------------------- /docs/zh/status.md: -------------------------------------------------------------------------------- 1 | # 状态API 2 | 3 | 状态API为客户端的机器人模块提供必要数据,目前包括以下API 4 | 5 | - init 获得机器人所有初始数据 6 | - refresh 机器人数据更新数据 7 | 8 | ## 实现 9 | 10 | > **必选** 11 | > 服务器端使用websocket通讯时,`init`将获得所有初始数据并初始化客户端,websocket 通过广播不断将`refrsh`数据传递给客户端 12 | 13 | ## API列表 14 | 15 | ### - init 16 | 17 | 获取当前机器人所在初始数据 18 | 19 | #### 请求参数 20 | 21 | > 用户初次连接机器人成功时,服务器将主动推送。 22 | > 用户设备重新连接(比如浏览器移动设备resume事件)也会主动推送 23 | 24 | ```javascript 25 | { 26 | "action": "init", 27 | "apiKey":"YOUR API KEY" 28 | } 29 | ``` 30 | 31 | #### 返回结果 32 | 33 | ```javascript 34 | { 35 | "exchange": { //交易所 36 | "name": "sim", //交易所名称 'sim'为模拟交易 37 | "makerFee": 0.1, //交易所市价费率 38 | "takerFee": 0.1//交易所限价费率 39 | }, 40 | "symbols": [ // 监控池交易对 41 | { 42 | "product_id": "ETH-USDT", //交易对名称 43 | "price": 1858.08, //价格 44 | "normalized": "mexc.ETH-USDT",//全称 45 | "min_size": "0.00001",//最小交易价格 46 | "asset": "ETH", 47 | "currency": "USDT", 48 | "assetCaptial": 0, 49 | "leverage": 10,//杠杆大小 50 | "isolated": false,//是否全仓 51 | "usdtProfit": 0,//USDT 利润 52 | "dynamicProfit": 0,//未实现 USDT 利润 53 | "dynamicUsdtProfit": 0,//未实现 USDT 利润率 54 | "profit": 0,//USDT 利润率 55 | "signal": null,//信号 包括 'buying','selling','bought','sold' 56 | "win": 0,//赢次数 57 | "lost": 0,//输次数 58 | "winLostRate": 0,//赢率 59 | "trades": [{//成交订单列表 60 | "order_id": 1001, //订单ID 61 | "time": 1681111866476,//订单时间 62 | "execution_time": 5001,//订单执行时间 63 | "slippage": 0,//订单滑点 64 | "type": "buy",//订单类型 buy or sell 65 | "size": "0.10757",//订单数量 66 | "fee": 0.19980051799999998,//订单费用 usdt计价 67 | "price": "1857.40", //订单成交价 68 | "order_type": "maker",//订单成交方式 'maker' 或 'taker' 69 | "action": "BollingerBands_buy_long",//订单成交策略 70 | "profit": -0.0009999999999999998, //订单利润 71 | "usdtProfit": -0.19980051799999998,//订单利润率 72 | "position_side": "long",//订单多还是空 'long' 或 'short' 73 | }, 74 | ... 75 | ], 76 | "lastTradeTime": 0,//最后交易时间 77 | "klines": [//K线数据 78 | { 79 | "period_id": "m28018427", 80 | "time": 1681105620000, 81 | "size": "1m", 82 | "close_time": 1681105679999, 83 | "open": 1863.3, 84 | "high": 1863.38, 85 | "low": 1862.22, 86 | "close": 1862.22, 87 | "volume": 45.16688, 88 | "strategy": { //K线中的策略数据 89 | "BollingerBands_buyCrossCount": 0,//策略BollingerBands同一周期内买点次数 90 | "BollingerBands_sellCrossCount": 0,//策略BollingerBands同一周期内卖点次数 91 | "BollingerBands_buy": false,//策略BollingerBands是否有买点 92 | "BollingerBands_sell": false//策略BollingerBands是否有卖点 93 | } 94 | }, 95 | ... 96 | ] 97 | }, 98 | ... 99 | ], 100 | "status": { //机器人状态 101 | "hasConfig": true,//是否实现配置模块 102 | "hasStrategy": true,//是否实现策略模块 103 | "hasMarket": true,//是否实现市场模块 104 | "hasBacktest": true,//是否实现回测模块 105 | "tradeListLen": 1,//交易中交易对数量 106 | "startCapital": 1000,//初始资金 107 | "currentCapital": 800.10957177,//当前可用资金 108 | "tradeNum": 12,//成交数量 109 | "dynamicUsdtProfit": -0.0290142,//未实现USDT利润 110 | "dynamicProfit": -0.0000290142,//未实现USDT利润率 111 | "usdtProfit": -0.19980051799999998,//USDT利润 112 | "profit": -0.000199800518,//利润率 113 | "exchange": "mexc",//当前交易所 114 | "startTime": 1681111671975,//机器人启动时间 115 | "timeZoneOffset": -480,//服务器时间偏移 116 | "status": "work",//当前机器人状态, 117 | "win": 4, 118 | "lost": 1, 119 | "winLostRate": 0.8, 120 | "totalCapital":999.32 //当前资金,包括已实现与未实现利润 121 | } 122 | } 123 | ``` 124 | 125 | ### - refresh 126 | 127 | 获取当前机器人实时更新数据 128 | 129 | > 服务器定时向客户端广播实时数据 130 | > 特定事件发生时可向客户端广播数据,比如订单成交时 131 | 132 | #### 请求参数 133 | 134 | ```javascript 135 | { 136 | "action": "refresh", 137 | "apiKey": "YOUR API KEY" 138 | } 139 | ``` 140 | 141 | #### 返回结果 142 | 143 | ```javascript 144 | { 145 | "action": "refresh", 146 | "data": { 147 | "symbols": [ //所有交易对 148 | { 149 | "product_id": "ETH-USDT", //交易对名称 150 | "price": 1858.08, //价格 151 | "normalized": "mexc.ETH-USDT",//全称 152 | "min_size": "0.00001",//最小交易价格 153 | "asset": "ETH", 154 | "currency": "USDT", 155 | "assetCaptial": 0, 156 | "leverage": 10,//杠杆大小 157 | "isolated": false,//是否全仓 158 | "usdtProfit": 0,//USDT 利润 159 | "dynamicProfit": 0,//未实现 USDT 利润 160 | "dynamicUsdtProfit": 0,//未实现 USDT 利润率 161 | "profit": 0,//USDT 利润率 162 | "signal": null,//信号 包括 'buying','selling','bought','sold' 163 | "win": 0,//赢次数 164 | "lost": 0,//输次数 165 | "winLostRate": 0,//赢率 166 | "trades": [{//成交订单列表 167 | "order_id": 1001, //订单ID 168 | "time": 1681111866476,//订单时间 169 | "execution_time": 5001,//订单执行时间 170 | "slippage": 0,//订单滑点 171 | "type": "buy",//订单类型 buy or sell 172 | "size": "0.10757",//订单数量 173 | "fee": 0.19980051799999998,//订单费用 usdt计价 174 | "price": "1857.40", //订单成交价 175 | "order_type": "maker",//订单成交方式 'maker' 或 'taker' 176 | "action": "BollingerBands_buy_long",//订单成交策略 177 | "profit": -0.0009999999999999998, //订单利润 178 | "usdtProfit": -0.19980051799999998,//订单利润率 179 | "position_side": "long",//订单多还是空 'long' 或 'short' 180 | }, 181 | ... 182 | ], 183 | "lastTradeTime": 0,//最后交易时间 184 | "klines": [//K线数据 185 | { 186 | "period_id": "m28018427", 187 | "time": 1681105620000, 188 | "size": "1m", 189 | "close_time": 1681105679999, 190 | "open": 1863.3, 191 | "high": 1863.38, 192 | "low": 1862.22, 193 | "close": 1862.22, 194 | "volume": 45.16688, 195 | "strategy": { //K线中的策略数据 196 | "BollingerBands_buyCrossCount": 0,//策略BollingerBands同一周期内买点次数 197 | "BollingerBands_sellCrossCount": 1,//策略BollingerBands同一周期内卖点次数 198 | "BollingerBands_buy": false,//策略BollingerBands是否有买点 199 | "BollingerBands_sell": false//策略BollingerBands是否有卖点 200 | "middle": 1856.3892857142853,//布林线中轨 201 | "upper": 1858.8566899522384,//布林线上轨 202 | "lower": 1853.9218814763321,//布林线轨 203 | "pb": 0.8203192775226102,//布林带偏移 204 | "pw": 0.26582832134842305,//布林带宽度 205 | } 206 | } 207 | ... 208 | ] 209 | }, 210 | ... 211 | ], 212 | "status": { //机器人当前状态 213 | "tradeListLen": 1,//交易中交易对数量 214 | "startCapital": 1000,//初始资金 215 | "currentCapital": 800.10957177,//当前可用资金 216 | "tradeNum": 12,//成交数量 217 | "dynamicUsdtProfit": -0.0290142,//未实现USDT利润 218 | "dynamicProfit": -0.0000290142,//未实现USDT利润率 219 | "usdtProfit": -0.19980051799999998,//USDT利润 220 | "profit": -0.000199800518,//利润率 221 | "exchange": "mexc",//当前交易所 222 | "startTime": 1681111671975,//机器人启动时间 223 | "timeZoneOffset": -480,//服务器时间偏移 224 | "status": "work",//当前机器人状态, 225 | "win": 4, 226 | "lost": 1, 227 | "winLostRate": 0.8, 228 | "totalCapital":999.32 //当前资金,包括已实现与未实现利润 229 | } 230 | } 231 | } 232 | ``` 233 | -------------------------------------------------------------------------------- /docs/zh/strategy.md: -------------------------------------------------------------------------------- 1 | # 策略API 2 | 3 | 策略API为客户端的策略模块提供必要数据,通过策略模块,您在服务器的所有策略均可通过客户端进行实时更新。目前包括以下API 4 | 5 | - init 获得策略列表与策略值 6 | - updateConfig 更新策略 7 | 8 | ## 必需实现 9 | 10 | > **可选** 11 | > 您需要先启用配置模块. 12 | > 如果不实现此API,客户端将不会有策略模块. 13 | > 如果未实现此API,在状态API请将机器人状态的`init`中请将`hasStrategy`设置为`false` 14 | 15 | ## 更新流程 16 | 17 | - 在`init`事件中传递策略列表 18 | - 通过策略设置在客户端生成相关联的UI界面 19 | - 通过UI界面修改策略并通过`updateConfig`更新服务器端值 20 | 21 | ## API列表 22 | 23 | ### - init 24 | 25 | 当使用策略模块时,策略列表与策略参数将通过`init`传递至客户端 26 | 27 | #### 请求参数 28 | 29 | > 用户初次连接机器人成功时,服务器将主动推送。 30 | > 用户设备重新连接(比如浏览器移动设备resume事件)也会主动推送 31 | 32 | ```javascript 33 | { 34 | "action": "init", 35 | "apiKey":"YOUR API KEY" 36 | } 37 | ``` 38 | 39 | #### 返回结果 40 | 41 | ```javascript 42 | { 43 | "options": { 44 | "strategy": Object,//当前策略会通过配置值传递至客户端 45 | ... 46 | }, 47 | "strategies": [//策略列表 48 | { 49 | "id": "BollingerBands",// 策略ID 50 | "name": "BollingerBands",//策略名称 51 | "des": "BollingerBands",//策略描述 52 | "editable": false,//可编辑 53 | "group": "custom",//策略分组 54 | "order": 20,//策略权重 55 | "strategies": [//子策略,本示例使用布林带与RSI组合来判断买卖点 56 | { 57 | "name": "BollingerBands",//布林带 58 | "group": "volatility",//分组 59 | "input": [//输入 60 | { 61 | "name": "period",//布林带周期 62 | "type": "number",//数值类型 63 | "step": [//最大最小与步长 64 | 2, 65 | 100, 66 | 1 67 | ], 68 | "value": 14//默认值 69 | }, 70 | { 71 | "name": "stdDev",//布林带偏移 72 | "type": "number", 73 | "step": [ 74 | -1, 75 | 30, 76 | 1 77 | ], 78 | "value": 2 79 | }, 80 | { 81 | "name": "valType",//输入数据 82 | "type": "array",//数组类型,可多选 83 | "list": [ 84 | "open", 85 | "high", 86 | "low", 87 | "close", 88 | "volume" 89 | ], 90 | "value": [ 91 | "close"//默认使用收盘价 92 | ] 93 | } 94 | ], 95 | "output": [//输出 96 | { 97 | "name": "upper",//上轨 98 | "report": true,//在服务端report中显示 99 | "show": true,//在客户端显示 100 | "pos": "main",//显示在主图上 101 | "type": "line"//显示类型为线图 102 | }, 103 | { 104 | "name": "middle", 105 | "report": true, 106 | "show": true, 107 | "pos": "main", 108 | "type": "line" 109 | }, 110 | { 111 | "name": "lower", 112 | "report": true, 113 | "show": true, 114 | "pos": "main", 115 | "type": "line" 116 | }, 117 | { 118 | "name": "pw", 119 | "report": true, 120 | "mark": true,//买卖点将显示在本图 121 | "show": true, 122 | "pos": "sub",//显示在副图上 123 | "type": "line" 124 | }, 125 | { 126 | "name": "signals",//买卖点信息 127 | "report": false, 128 | "show": true, 129 | "pos": "sub", 130 | "type": "marker"//显示为标识 131 | } 132 | ], 133 | "buyPoint": {//买点 134 | "connect": "base",//多个子策略时,本策略为基础策略 135 | "source": "close",//收盘价 136 | "op": "crossUp",//上穿 137 | "target": "lower"//下轨 138 | }, 139 | "sellPoint": {//卖点 140 | "connect": "base",//多个子策略时,本策略为基础策略 141 | "source": "close",//收盘价 142 | "op": "crossDown",//下穿 143 | "target": "upper"//上轨 144 | } 145 | }, 146 | { 147 | "name": "RSI",//另一个子策略名称 148 | "des": "RSI", 149 | "editable": false, 150 | "group": "oscillators", 151 | "input": [ 152 | { 153 | "name": "period", 154 | "type": "number", 155 | "step": [ 156 | 2, 157 | 100, 158 | 1 159 | ], 160 | "value": 8 161 | }, 162 | { 163 | "name": "overBoughtThreshold",//超买点 164 | "type": "number", 165 | "step": [ 166 | 0, 167 | 100, 168 | 1 169 | ], 170 | "value": 75, 171 | "show": true, 172 | "pos": "bottom", 173 | "owner": "RSI",//显示图为RSI 174 | "priceline": true //显示类型为价格线 175 | }, 176 | { 177 | "name": "overSoldThreshold",//超卖点 178 | "type": "number", 179 | "step": [ 180 | 0, 181 | 100, 182 | 1 183 | ], 184 | "value": 25, 185 | "show": true, 186 | "pos": "bottom", 187 | "owner": "RSI",//显示图为RSI 188 | "priceline": true//显示类型为价格线 189 | }, 190 | { 191 | "name": "valType", 192 | "type": "array", 193 | "list": [ 194 | "open", 195 | "high", 196 | "low", 197 | "close", 198 | "volume" 199 | ], 200 | "value": [ 201 | "close" 202 | ] 203 | } 204 | ], 205 | "output": [ 206 | { 207 | "name": "RSI", 208 | "report": true, 209 | "show": true, 210 | "pos": "bottom",//显示在底图中 211 | "type": "line", 212 | "mark": true 213 | }, 214 | { 215 | "name": "signals", 216 | "report": false, 217 | "show": true, 218 | "pos": "bottom",//显示在底图中 219 | "type": "marker" 220 | } 221 | ], 222 | "buyPoint": { 223 | "connect": "and",//买点之间为和关系 'none','and','or', 224 | "source": "RSI",//RSI 225 | "op": "crossUp",//上穿 226 | "target": "overSoldThreshold"//超卖点 227 | }, 228 | "sellPoint": { 229 | "connect": "or",//卖点之间为或关系 'none'为不启用,'and','or', 230 | "source": "RSI",//RSI 231 | "op": "crossDown",//下穿 232 | "target": "overBoughtThreshold"//超买点 233 | } 234 | } 235 | ] 236 | }, 237 | ... 238 | ] 239 | } 240 | ``` 241 | 242 | ### - updateConfig 243 | 244 | 更新机器人策略参数 245 | 246 | #### 请求参数 247 | 248 | ```javascript 249 | { 250 | "action": "updateConfig", 251 | "restart": true, //本次更新需要重启机器人 252 | "data": { 253 | "strategy": Object, //更新策略 254 | }, 255 | "apiKey": "YOUR API KEY" 256 | } 257 | ``` 258 | 259 | #### 返回结果 260 | 261 | ```json 262 | { 263 | "action": "updateConfig", 264 | "data":Object, //返回全部配置参数 方便更 265 | "toast": "trade.updateConfigOk" 266 | } 267 | ``` 268 | 269 | > 一些示例的策略文件 270 | 271 | ````javascript 272 | [ 273 | { 274 | "id": "RSI", 275 | "name": "RSI", 276 | "des": "RSI", 277 | "editable": false, 278 | "group": "custom", 279 | "order": 10, 280 | "strategies": [ 281 | { 282 | "name": "RSI", 283 | "des": "RSI", 284 | "editable": false, 285 | "group": "oscillators", 286 | "input": [ 287 | { 288 | "name": "period", 289 | "type": "number", 290 | "step": [ 291 | 2, 292 | 100, 293 | 1 294 | ], 295 | "value": 8 296 | }, 297 | { 298 | "name": "overBoughtThreshold", 299 | "type": "number", 300 | "step": [ 301 | 0, 302 | 100, 303 | 1 304 | ], 305 | "value": 75, 306 | "show": true, 307 | "pos": "bottom", 308 | "owner": "RSI", 309 | "priceline": true 310 | }, 311 | { 312 | "name": "overSoldThreshold", 313 | "type": "number", 314 | "step": [ 315 | 0, 316 | 100, 317 | 1 318 | ], 319 | "value": 25, 320 | "show": true, 321 | "pos": "bottom", 322 | "owner": "RSI", 323 | "priceline": true 324 | }, 325 | { 326 | "name": "valType", 327 | "type": "array", 328 | "list": [ 329 | "open", 330 | "high", 331 | "low", 332 | "close", 333 | "volume" 334 | ], 335 | "value": [ 336 | "close" 337 | ] 338 | } 339 | ], 340 | "output": [ 341 | { 342 | "name": "RSI", 343 | "report": true, 344 | "show": true, 345 | "pos": "bottom", 346 | "type": "line", 347 | "mark": true 348 | }, 349 | { 350 | "name": "signals", 351 | "report": false, 352 | "show": true, 353 | "pos": "bottom", 354 | "type": "marker" 355 | } 356 | ], 357 | "buyPoint": { 358 | "connect": "base", 359 | "source": "RSI", 360 | "op": "crossUp", 361 | "target": "overSoldThreshold" 362 | }, 363 | "sellPoint": { 364 | "connect": "base", 365 | "source": "RSI", 366 | "op": "crossDown", 367 | "target": "overBoughtThreshold" 368 | } 369 | } 370 | ] 371 | }, 372 | { 373 | "id": "BollingerBands", 374 | "name": "BollingerBands", 375 | "des": "BollingerBands", 376 | "editable": false, 377 | "group": "custom", 378 | "order": 20, 379 | "strategies": [ 380 | { 381 | "name": "BollingerBands", 382 | "group": "volatility", 383 | "input": [ 384 | { 385 | "name": "period", 386 | "type": "number", 387 | "step": [ 388 | 2, 389 | 100, 390 | 1 391 | ], 392 | "value": 14 393 | }, 394 | { 395 | "name": "stdDev", 396 | "type": "number", 397 | "step": [ 398 | -1, 399 | 30, 400 | 1 401 | ], 402 | "value": 2 403 | }, 404 | { 405 | "name": "valType", 406 | "type": "array", 407 | "list": [ 408 | "open", 409 | "high", 410 | "low", 411 | "close", 412 | "volume" 413 | ], 414 | "value": [ 415 | "close" 416 | ] 417 | } 418 | ], 419 | "output": [ 420 | { 421 | "name": "upper", 422 | "report": true, 423 | "show": true, 424 | "pos": "main", 425 | "type": "line" 426 | }, 427 | { 428 | "name": "middle", 429 | "report": true, 430 | "show": true, 431 | "pos": "main", 432 | "type": "line" 433 | }, 434 | { 435 | "name": "lower", 436 | "report": true, 437 | "show": true, 438 | "pos": "main", 439 | "type": "line" 440 | }, 441 | { 442 | "name": "pw", 443 | "report": true, 444 | "mark": true, 445 | "show": true, 446 | "pos": "sub", 447 | "type": "line" 448 | }, 449 | { 450 | "name": "signals", 451 | "report": false, 452 | "show": true, 453 | "pos": "sub", 454 | "type": "marker" 455 | } 456 | ], 457 | "buyPoint": { 458 | "connect": "base", 459 | "source": "close", 460 | "op": "crossUp", 461 | "target": "lower" 462 | }, 463 | "sellPoint": { 464 | "connect": "base", 465 | "source": "close", 466 | "op": "crossDown", 467 | "target": "upper" 468 | } 469 | }, 470 | { 471 | "name": "RSI", 472 | "des": "RSI", 473 | "editable": false, 474 | "group": "oscillators", 475 | "input": [ 476 | { 477 | "name": "period", 478 | "type": "number", 479 | "step": [ 480 | 2, 481 | 100, 482 | 1 483 | ], 484 | "value": 8 485 | }, 486 | { 487 | "name": "overBoughtThreshold", 488 | "type": "number", 489 | "step": [ 490 | 0, 491 | 100, 492 | 1 493 | ], 494 | "value": 75, 495 | "show": true, 496 | "pos": "bottom", 497 | "owner": "RSI", 498 | "priceline": true 499 | }, 500 | { 501 | "name": "overSoldThreshold", 502 | "type": "number", 503 | "step": [ 504 | 0, 505 | 100, 506 | 1 507 | ], 508 | "value": 25, 509 | "show": true, 510 | "pos": "bottom", 511 | "owner": "RSI", 512 | "priceline": true 513 | }, 514 | { 515 | "name": "valType", 516 | "type": "array", 517 | "list": [ 518 | "open", 519 | "high", 520 | "low", 521 | "close", 522 | "volume" 523 | ], 524 | "value": [ 525 | "close" 526 | ] 527 | } 528 | ], 529 | "output": [ 530 | { 531 | "name": "RSI", 532 | "report": true, 533 | "show": true, 534 | "pos": "bottom", 535 | "type": "line", 536 | "mark": true 537 | }, 538 | { 539 | "name": "signals", 540 | "report": false, 541 | "show": true, 542 | "pos": "bottom", 543 | "type": "marker" 544 | } 545 | ], 546 | "buyPoint": { 547 | "connect": "none", 548 | "source": "RSI", 549 | "op": "crossUp", 550 | "target": "overSoldThreshold" 551 | }, 552 | "sellPoint": { 553 | "connect": "none", 554 | "source": "RSI", 555 | "op": "crossDown", 556 | "target": "overBoughtThreshold" 557 | } 558 | } 559 | ] 560 | }, 561 | { 562 | "id": "PSAR", 563 | "name": "PSAR", 564 | "des": "PSAR", 565 | "editable": false, 566 | "group": "custom", 567 | "order": 30, 568 | "strategies": [ 569 | { 570 | "name": "PSAR", 571 | "group": "momentum", 572 | "input": [ 573 | { 574 | "name": "step", 575 | "type": "number", 576 | "step": [ 577 | 0.01, 578 | 1, 579 | 0.005 580 | ], 581 | "value": 0.02 582 | }, 583 | { 584 | "name": "max", 585 | "type": "number", 586 | "step": [ 587 | 0.05, 588 | 1, 589 | 0.05 590 | ], 591 | "value": 0.2 592 | }, 593 | { 594 | "name": "valType", 595 | "type": "array", 596 | "list": [ 597 | "open", 598 | "high", 599 | "low", 600 | "close", 601 | "volume" 602 | ], 603 | "value": [ 604 | "high", 605 | "low" 606 | ] 607 | } 608 | ], 609 | "output": [ 610 | { 611 | "name": "PSAR", 612 | "report": true, 613 | "mark": false, 614 | "show": true, 615 | "pos": "main", 616 | "type": "line", 617 | "dot": true 618 | }, 619 | { 620 | "name": "trend", 621 | "report": true, 622 | "mark": true, 623 | "show": true, 624 | "pos": "sub", 625 | "type": "line" 626 | }, 627 | { 628 | "name": "signals", 629 | "report": false, 630 | "show": true, 631 | "pos": "main", 632 | "type": "marker" 633 | } 634 | ], 635 | "buyPoint": { 636 | "connect": "base", 637 | "source": "PSAR", 638 | "op": "crossDown", 639 | "target": "close" 640 | }, 641 | "sellPoint": { 642 | "connect": "base", 643 | "source": "PSAR", 644 | "op": "crossUp", 645 | "target": "close" 646 | } 647 | }, 648 | { 649 | "name": "RSI", 650 | "des": "RSI", 651 | "editable": false, 652 | "group": "oscillators", 653 | "input": [ 654 | { 655 | "name": "period", 656 | "type": "number", 657 | "step": [ 658 | 2, 659 | 100, 660 | 1 661 | ], 662 | "value": 8 663 | }, 664 | { 665 | "name": "overBoughtThreshold", 666 | "type": "number", 667 | "step": [ 668 | 0, 669 | 100, 670 | 1 671 | ], 672 | "value": 75, 673 | "show": true, 674 | "pos": "bottom", 675 | "owner": "RSI", 676 | "priceline": true 677 | }, 678 | { 679 | "name": "overSoldThreshold", 680 | "type": "number", 681 | "step": [ 682 | 0, 683 | 100, 684 | 1 685 | ], 686 | "value": 25, 687 | "show": true, 688 | "pos": "bottom", 689 | "owner": "RSI", 690 | "priceline": true 691 | }, 692 | { 693 | "name": "valType", 694 | "type": "array", 695 | "list": [ 696 | "open", 697 | "high", 698 | "low", 699 | "close", 700 | "volume" 701 | ], 702 | "value": [ 703 | "close" 704 | ] 705 | } 706 | ], 707 | "output": [ 708 | { 709 | "name": "RSI", 710 | "report": true, 711 | "show": true, 712 | "pos": "bottom", 713 | "type": "line", 714 | "mark": true 715 | }, 716 | { 717 | "name": "signals", 718 | "report": false, 719 | "show": true, 720 | "pos": "bottom", 721 | "type": "marker" 722 | } 723 | ], 724 | "buyPoint": { 725 | "connect": "none", 726 | "source": "RSI", 727 | "op": "crossUp", 728 | "target": "overSoldThreshold" 729 | }, 730 | "sellPoint": { 731 | "connect": "none", 732 | "source": "RSI", 733 | "op": "crossDown", 734 | "target": "overBoughtThreshold" 735 | } 736 | } 737 | ] 738 | }, 739 | { 740 | "id": "MACD", 741 | "name": "MACD", 742 | "des": "MACD", 743 | "editable": false, 744 | "group": "custom", 745 | "order": 40, 746 | "strategies": [ 747 | { 748 | "name": "MACD", 749 | "group": "moving_averages", 750 | "input": [ 751 | { 752 | "name": "fastPeriod", 753 | "type": "number", 754 | "step": [ 755 | 1, 756 | 200, 757 | 1 758 | ], 759 | "value": 5 760 | }, 761 | { 762 | "name": "slowPeriod", 763 | "type": "number", 764 | "step": [ 765 | 1, 766 | 200, 767 | 1 768 | ], 769 | "value": 8 770 | }, 771 | { 772 | "name": "signalPeriod", 773 | "type": "number", 774 | "step": [ 775 | 1, 776 | 200, 777 | 1 778 | ], 779 | "value": 3 780 | }, 781 | { 782 | "name": "SimpleMAOscillator", 783 | "type": "bool", 784 | "value": false 785 | }, 786 | { 787 | "name": "SimpleMASignal", 788 | "type": "bool", 789 | "value": false 790 | }, 791 | { 792 | "name": "valType", 793 | "type": "array", 794 | "list": [ 795 | "open", 796 | "high", 797 | "low", 798 | "close", 799 | "volume" 800 | ], 801 | "value": [ 802 | "close" 803 | ] 804 | } 805 | ], 806 | "output": [ 807 | { 808 | "name": "MACD", 809 | "report": true, 810 | "show": true, 811 | "pos": "sub", 812 | "type": "line" 813 | }, 814 | { 815 | "name": "histogram", 816 | "report": true, 817 | "show": true, 818 | "pos": "sub", 819 | "mark": true, 820 | "type": "line" 821 | }, 822 | { 823 | "name": "signal", 824 | "report": true, 825 | "show": true, 826 | "pos": "sub", 827 | "type": "line" 828 | }, 829 | { 830 | "name": "signals", 831 | "report": false, 832 | "show": true, 833 | "pos": "sub", 834 | "type": "marker" 835 | } 836 | ], 837 | "buyPoint": { 838 | "connect": "base", 839 | "source": "histogram", 840 | "op": "crossUp", 841 | "target": 0 842 | }, 843 | "sellPoint": { 844 | "connect": "base", 845 | "source": "histogram", 846 | "op": "crossDown", 847 | "target": 0 848 | } 849 | }, 850 | { 851 | "name": "RSI", 852 | "des": "RSI", 853 | "editable": false, 854 | "group": "oscillators", 855 | "input": [ 856 | { 857 | "name": "period", 858 | "type": "number", 859 | "step": [ 860 | 2, 861 | 100, 862 | 1 863 | ], 864 | "value": 8 865 | }, 866 | { 867 | "name": "overBoughtThreshold", 868 | "type": "number", 869 | "step": [ 870 | 0, 871 | 100, 872 | 1 873 | ], 874 | "value": 75, 875 | "show": true, 876 | "pos": "bottom", 877 | "owner": "RSI", 878 | "priceline": true 879 | }, 880 | { 881 | "name": "overSoldThreshold", 882 | "type": "number", 883 | "step": [ 884 | 0, 885 | 100, 886 | 1 887 | ], 888 | "value": 25, 889 | "show": true, 890 | "pos": "bottom", 891 | "owner": "RSI", 892 | "priceline": true 893 | }, 894 | { 895 | "name": "valType", 896 | "type": "array", 897 | "list": [ 898 | "open", 899 | "high", 900 | "low", 901 | "close", 902 | "volume" 903 | ], 904 | "value": [ 905 | "close" 906 | ] 907 | } 908 | ], 909 | "output": [ 910 | { 911 | "name": "RSI", 912 | "report": true, 913 | "show": true, 914 | "pos": "bottom", 915 | "type": "line", 916 | "mark": true 917 | }, 918 | { 919 | "name": "signals", 920 | "report": false, 921 | "show": true, 922 | "pos": "bottom", 923 | "type": "marker" 924 | } 925 | ], 926 | "buyPoint": { 927 | "connect": "none", 928 | "source": "RSI", 929 | "op": "crossUp", 930 | "target": "overSoldThreshold" 931 | }, 932 | "sellPoint": { 933 | "connect": "none", 934 | "source": "RSI", 935 | "op": "crossDown", 936 | "target": "overBoughtThreshold" 937 | } 938 | } 939 | ] 940 | }, 941 | { 942 | "id": "CandleStick", 943 | "name": "CandleStick", 944 | "des": "CandleStick", 945 | "editable": false, 946 | "group": "custom", 947 | "order": 50, 948 | "strategies": [ 949 | { 950 | "name": "CandleStick", 951 | "group": "candlestick", 952 | "input": [ 953 | { 954 | "name": "buyPatterns", 955 | "type": "array", 956 | "list": [ 957 | "BullishEngulfingPattern", 958 | "DownsideTasukiGap", 959 | "BullishHarami", 960 | "BullishHaramiCross", 961 | "MorningDojiStar", 962 | "MorningStar", 963 | "BullishMarubozu", 964 | "PiercingLine", 965 | "ThreeWhiteSoldiers", 966 | "BullishHammerStick", 967 | "BullishInvertedHammerStick", 968 | "HammerPattern", 969 | "HammerPatternUnconfirmed", 970 | "TweezerBottom" 971 | ], 972 | "value": [ 973 | "ThreeWhiteSoldiers", 974 | "HammerPattern", 975 | "TweezerBottom" 976 | ] 977 | }, 978 | { 979 | "name": "sellPatterns", 980 | "type": "array", 981 | "list": [ 982 | "BearishEngulfingPattern", 983 | "BearishHarami", 984 | "BearishHaramiCross", 985 | "EveningDojiStar", 986 | "EveningStar", 987 | "BearishMarubozu", 988 | "ThreeBlackCrows", 989 | "BearishHammerStick", 990 | "BearishInvertedHammerStick", 991 | "HangingMan", 992 | "HangingManUnconfirmed", 993 | "ShootingStar", 994 | "ShootingStarUnconfirmed", 995 | "TweezerTop" 996 | ], 997 | "value": [ 998 | "ThreeBlackCrows", 999 | "HangingMan", 1000 | "ShootingStar", 1001 | "TweezerTop" 1002 | ] 1003 | }, 1004 | { 1005 | "name": "valType", 1006 | "type": "array", 1007 | "list": [ 1008 | "open", 1009 | "high", 1010 | "low", 1011 | "close", 1012 | "volume" 1013 | ], 1014 | "value": [ 1015 | "close", 1016 | "high", 1017 | "low", 1018 | "open" 1019 | ] 1020 | } 1021 | ], 1022 | "output": [ 1023 | { 1024 | "name": "pattern", 1025 | "mark": true, 1026 | "report": true, 1027 | "show": true, 1028 | "pos": "sub", 1029 | "type": "line" 1030 | }, 1031 | { 1032 | "name": "patternname", 1033 | "report": true, 1034 | "show": false, 1035 | "pos": "sub", 1036 | "type": "none" 1037 | }, 1038 | { 1039 | "name": "signals", 1040 | "report": false, 1041 | "show": true, 1042 | "pos": "sub", 1043 | "type": "marker" 1044 | } 1045 | ], 1046 | "buyPoint": { 1047 | "connect": "base", 1048 | "source": "pattern", 1049 | "op": "equal", 1050 | "target": -1 1051 | }, 1052 | "sellPoint": { 1053 | "connect": "base", 1054 | "source": "pattern", 1055 | "op": "equal", 1056 | "target": 1 1057 | } 1058 | }, 1059 | { 1060 | "name": "RSI", 1061 | "des": "RSI", 1062 | "editable": false, 1063 | "group": "oscillators", 1064 | "input": [ 1065 | { 1066 | "name": "period", 1067 | "type": "number", 1068 | "step": [ 1069 | 2, 1070 | 100, 1071 | 1 1072 | ], 1073 | "value": 8 1074 | }, 1075 | { 1076 | "name": "overBoughtThreshold", 1077 | "type": "number", 1078 | "step": [ 1079 | 0, 1080 | 100, 1081 | 1 1082 | ], 1083 | "value": 75, 1084 | "show": true, 1085 | "pos": "bottom", 1086 | "owner": "RSI", 1087 | "priceline": true 1088 | }, 1089 | { 1090 | "name": "overSoldThreshold", 1091 | "type": "number", 1092 | "step": [ 1093 | 0, 1094 | 100, 1095 | 1 1096 | ], 1097 | "value": 25, 1098 | "show": true, 1099 | "pos": "bottom", 1100 | "owner": "RSI", 1101 | "priceline": true 1102 | }, 1103 | { 1104 | "name": "valType", 1105 | "type": "array", 1106 | "list": [ 1107 | "open", 1108 | "high", 1109 | "low", 1110 | "close", 1111 | "volume" 1112 | ], 1113 | "value": [ 1114 | "close" 1115 | ] 1116 | } 1117 | ], 1118 | "output": [ 1119 | { 1120 | "name": "RSI", 1121 | "report": true, 1122 | "show": true, 1123 | "pos": "bottom", 1124 | "type": "line", 1125 | "mark": true 1126 | }, 1127 | { 1128 | "name": "signals", 1129 | "report": false, 1130 | "show": true, 1131 | "pos": "bottom", 1132 | "type": "marker" 1133 | } 1134 | ], 1135 | "buyPoint": { 1136 | "connect": "none", 1137 | "source": "RSI", 1138 | "op": "crossUp", 1139 | "target": "overSoldThreshold" 1140 | }, 1141 | "sellPoint": { 1142 | "connect": "none", 1143 | "source": "RSI", 1144 | "op": "crossDown", 1145 | "target": "overBoughtThreshold" 1146 | } 1147 | } 1148 | ] 1149 | }, 1150 | { 1151 | "id": "CUSTOM", 1152 | "name": "CUSTOM", 1153 | "des": "CUSTOM", 1154 | "editable": false, 1155 | "group": "custom", 1156 | "order": 100, 1157 | "strategies": [ 1158 | { 1159 | "name": "PSAR", 1160 | "group": "momentum", 1161 | "input": [ 1162 | { 1163 | "name": "step", 1164 | "type": "number", 1165 | "step": [ 1166 | 0.01, 1167 | 1, 1168 | 0.005 1169 | ], 1170 | "value": 0.02 1171 | }, 1172 | { 1173 | "name": "max", 1174 | "type": "number", 1175 | "step": [ 1176 | 0.05, 1177 | 1, 1178 | 0.05 1179 | ], 1180 | "value": 0.2 1181 | }, 1182 | { 1183 | "name": "valType", 1184 | "type": "array", 1185 | "list": [ 1186 | "open", 1187 | "high", 1188 | "low", 1189 | "close", 1190 | "volume" 1191 | ], 1192 | "value": [ 1193 | "high", 1194 | "low" 1195 | ] 1196 | } 1197 | ], 1198 | "output": [ 1199 | { 1200 | "name": "PSAR", 1201 | "report": true, 1202 | "show": true, 1203 | "pos": "main", 1204 | "type": "line", 1205 | "dot": true 1206 | }, 1207 | { 1208 | "name": "trend", 1209 | "report": true, 1210 | "mark": true, 1211 | "show": true, 1212 | "pos": "sub", 1213 | "type": "line" 1214 | }, 1215 | { 1216 | "name": "signals", 1217 | "report": false, 1218 | "show": true, 1219 | "pos": "main", 1220 | "type": "marker" 1221 | } 1222 | ], 1223 | "buyPoint": { 1224 | "connect": "base", 1225 | "source": "PSAR", 1226 | "op": "crossDown", 1227 | "target": "close" 1228 | }, 1229 | "sellPoint": { 1230 | "connect": "base", 1231 | "source": "PSAR", 1232 | "op": "crossUp", 1233 | "target": "close" 1234 | } 1235 | }, 1236 | { 1237 | "name": "RSI", 1238 | "des": "RSI", 1239 | "editable": false, 1240 | "group": "oscillators", 1241 | "input": [ 1242 | { 1243 | "name": "period", 1244 | "type": "number", 1245 | "step": [ 1246 | 2, 1247 | 100, 1248 | 1 1249 | ], 1250 | "value": 8 1251 | }, 1252 | { 1253 | "name": "overBoughtThreshold", 1254 | "type": "number", 1255 | "step": [ 1256 | 0, 1257 | 100, 1258 | 1 1259 | ], 1260 | "value": 75, 1261 | "show": true, 1262 | "pos": "bottom", 1263 | "owner": "RSI", 1264 | "priceline": true 1265 | }, 1266 | { 1267 | "name": "overSoldThreshold", 1268 | "type": "number", 1269 | "step": [ 1270 | 0, 1271 | 100, 1272 | 1 1273 | ], 1274 | "value": 25, 1275 | "show": true, 1276 | "pos": "bottom", 1277 | "owner": "RSI", 1278 | "priceline": true 1279 | }, 1280 | { 1281 | "name": "valType", 1282 | "type": "array", 1283 | "list": [ 1284 | "open", 1285 | "high", 1286 | "low", 1287 | "close", 1288 | "volume" 1289 | ], 1290 | "value": [ 1291 | "close" 1292 | ] 1293 | } 1294 | ], 1295 | "output": [ 1296 | { 1297 | "name": "RSI", 1298 | "report": true, 1299 | "show": true, 1300 | "pos": "bottom", 1301 | "type": "line", 1302 | "mark": true 1303 | }, 1304 | { 1305 | "name": "signals", 1306 | "report": false, 1307 | "show": true, 1308 | "pos": "bottom", 1309 | "type": "marker" 1310 | } 1311 | ], 1312 | "buyPoint": { 1313 | "connect": "and", 1314 | "source": "RSI", 1315 | "op": "crossUp", 1316 | "target": "overSoldThreshold" 1317 | }, 1318 | "sellPoint": { 1319 | "connect": "and", 1320 | "source": "RSI", 1321 | "op": "crossDown", 1322 | "target": "overBoughtThreshold" 1323 | } 1324 | } 1325 | ] 1326 | } 1327 | ] 1328 | ```` 1329 | -------------------------------------------------------------------------------- /extensions/xcoin/README.md: -------------------------------------------------------------------------------- 1 | # Panacea's preferred server-side program XCoin 2 | 3 | XCoin implements all the APIs of Panacea, you can directly use XCoin as your background bot, or learn how to adapts your bot by learning the source code of XCoin 4 | 5 | ## Install 6 | 7 | copy `panacea` folder to your xcoin project `extensions/output/` folder 8 | 9 | ## About XCoin 10 | 11 | A simple and powerful trading bot based on nodejs 12 | 13 | ## Features 14 | 15 | - Support trading multiple trading pairs at the same time, as long as the server has enough computing power, theoretically you can trade all trading pairs at the same time. 16 | 17 | - Support all exchanges supported by [ccxt](https://github.com/ccxt/ccxt), [Binance](https://www.binance.com),[BinanceUsdm](https://www.binance.com), [Mexc](https://www.mexc.com/) have been fully tested. 18 | 19 | - Support all trading strategies supported by [technicalindicators](https://github.com/anandanand84/technicalindicators), easily extend new strategies through JSON files. 20 | 21 | - Supports futures trading and can control whether it is long or short or both trading. 22 | 23 | - Support multiple trading methods, automatic buying, manual buying, manual selling or full manual mode. 24 | 25 | - Supports monitoring of purchased items, blacklist, and dynamic addition of monitoring items 26 | 27 | - Support getting price updates on a separate thread, and support deploying multiple bots on the same machine on the same exchange. 28 | 29 | - Support real transactions, virtual transactions and backtest transactions 30 | 31 | - Support all mobile devices and desktop devices through [Panacea](https://github.com/markmind/panacea-api), control all the states and operations of the bot in real time 32 | 33 | - Based on [Zenbot](https://github.com/DeviaVir/zenbot), Supports most of the functions of zenbot. 34 | 35 | ## Documentation 36 | 37 | - [User Documentation](https://rainfu.github.io/xcoin) 38 | -------------------------------------------------------------------------------- /extensions/xcoin/README.zh-CN.md: -------------------------------------------------------------------------------- 1 | # 灵丹首选服务器端程序 XCoin 2 | 3 | XCoin实现了灵丹所有的API,您可以直接使用XCoin作为您的后台机器人,也可以通过学习XCoin的源码了解如何使用适配您的机器人 4 | 5 | ## 安装 6 | 7 | 复制 `panacea` 目录 to 您的XCoin项目的 `extensions/output/` 目录 8 | 9 | ## 关于XCoin 10 | 11 | 基于nodejs的简洁强大的交易机器人 12 | 13 | ## 功能特征 14 | 15 | - 支持同时交易多个交易对,只要服务器有足够算力,理论上你可以同时交易所有交易对. 16 | - 支持 [ccxt](https://github.com/ccxt/ccxt) 支持的所有交易所,[Binance](https://www.binance.com),[BinanceUsdm](https://www.binance.com),[Mexc](https://www.mexc.com/)已完整测试. 17 | - 支持 [technicalindicators](https://github.com/anandanand84/technicalindicators) 支持的所有交易策略,轻松通过JSON文件扩展新的策略. 18 | - 支持期货交易并可控制是多空双方还是仅交易多方,空方. 19 | - 支持多种交易方式,自动买,手动买,手动卖或完全手动模式. 20 | - 支持监控已购项目,支持黑名单,支持动态添加监控项目 21 | - 支持在单独线程上获取价格更新,支持同一机器同一交易所部署多个机器人. 22 | - 支持真实交易,虚拟交易及对交易进行回测 23 | - 基于 [Zenbot](https://github.com/DeviaVir/zenbot) ,支持 zenbot 的绝大部分功能. 24 | 25 | ## 文档 26 | 27 | - [用户文档](https://rainfu.github.io/xcoin) 28 | -------------------------------------------------------------------------------- /extensions/xcoin/panacea/api/api.js: -------------------------------------------------------------------------------- 1 | var { getInitData, getRefreshData } = require('./status') 2 | , { getBacktestList, delBacktest, getSimList, delSim, backtestSim } = require('./backtest') 3 | , { addSymbol, removeAllSymbol, removeSymbol, sellAll, buy, sell, getBalance, getDemoBot } = require('./operation') 4 | , { updateConfig, updateSymbolFuture } = require('./config') 5 | , { checkVersion } = require('./panacea') 6 | , { getProducts, getKlines, getTickers, getPickerNormal } = require('./market') 7 | module.exports = function api() { 8 | return { 9 | getInitData, 10 | getRefreshData, 11 | getBacktestList, 12 | delBacktest, 13 | getSimList, 14 | delSim, 15 | backtestSim, 16 | addSymbol, 17 | removeAllSymbol, 18 | removeSymbol, 19 | buy, 20 | sell, 21 | sellAll, 22 | updateConfig, 23 | updateSymbolFuture, 24 | checkVersion, 25 | getProducts, 26 | getKlines, 27 | getTickers, 28 | getPickerNormal, 29 | getBalance, 30 | getDemoBot 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /extensions/xcoin/panacea/api/backtest.js: -------------------------------------------------------------------------------- 1 | const collectionService = require('../../../../lib/mongo-service') 2 | , spawn = require('child_process').spawn 3 | , path = require('path') 4 | 5 | const getBacktestList = (message, cb, s, conf) => { 6 | let collectionServiceInstance = collectionService(conf) 7 | let bots = collectionServiceInstance.getBots() 8 | bots.find({ "status.status": 'finished' }).skip(message.data.from).limit(message.data.limit).sort({ startTime: -1 }).toArray((err, botArray) => { 9 | if (err) return 10 | let data = { 11 | action: message.action, 12 | data: botArray 13 | } 14 | if (cb) cb(data) 15 | }) 16 | } 17 | const delBacktest = (message, cb, s, conf) => { 18 | let collectionServiceInstance = collectionService(conf) 19 | let bots = collectionServiceInstance.getBots() 20 | bots.deleteOne({ "_id": message.data.id }).then((res) => { 21 | if (res.deletedCount) { 22 | let data = { 23 | action: message.action, 24 | data: { 25 | id: message.data.id 26 | }, 27 | toast: 'backtest.' + message.action + 'Ok' 28 | } 29 | if (cb) cb(data) 30 | } 31 | }) 32 | } 33 | const getSimList = (message, cb, s, conf) => { 34 | let simCollection = collectionService(conf).getSims() 35 | simCollection.find({ bid: message.data.bid }).skip(message.data.from).limit(message.data.limit).sort({ time: -1 }).toArray((err, simArray) => { 36 | console.log('getSimList', message.data, err, simArray) 37 | if (err) return 38 | let data = { 39 | action: message.action, 40 | data: simArray 41 | } 42 | if (cb) cb(data) 43 | }) 44 | } 45 | const delSim = (message, cb, s, conf) => { 46 | let collectionServiceInstance = collectionService(conf) 47 | let simList = collectionServiceInstance.getSims() 48 | simList.deleteOne({ "_id": message.data.id }).then((res) => { 49 | if (res.deletedCount) { 50 | let data = { 51 | action: message.action, 52 | data: { 53 | id: message.data.id 54 | }, 55 | toast: 'backtest.' + message.action + 'Ok' 56 | } 57 | if (cb) cb(data) 58 | } 59 | }) 60 | } 61 | const backtestSim = (message, cb) => { 62 | var xcoin_cmd = process.platform === 'win32' ? 'xcoin.bat' : 'xcoin.sh' 63 | var command_args = ['sim', message.data.exchange, '--bot', message.data.bid, '--sim_options', message.data.options] 64 | console.log('Start backtest for bot '.green) 65 | var simProcess = spawn(path.resolve(__dirname, '../../', xcoin_cmd), command_args) 66 | simProcess.stdout.pipe(process.stdout) 67 | simProcess.stderr.pipe(process.stderr) 68 | simProcess.on('exit', (code) => { 69 | if (code) { 70 | console.log('simProcess exit with code'.green, code) 71 | process.exit(code) 72 | return 73 | } 74 | let data = { 75 | action: message.action, 76 | toast: 'trade.' + message.action + 'Ok' 77 | } 78 | if (cb) cb(data) 79 | }) 80 | } 81 | module.exports = { 82 | backtestSim, 83 | getBacktestList, 84 | getSimList, 85 | delBacktest, 86 | delSim 87 | } -------------------------------------------------------------------------------- /extensions/xcoin/panacea/api/config.js: -------------------------------------------------------------------------------- 1 | 2 | var _ = require('lodash') 3 | , moment = require('moment') 4 | , debug = require('../../../../lib/debug') 5 | 6 | /** update config group */ 7 | const updateConfig = (message, cb, s) => { 8 | Object.assign(s.options, message.data) 9 | s.options.modified = message.data 10 | if (message.data.strategy) { 11 | s.options.strategy = message.data.strategy 12 | } 13 | if (!_.isUndefined(message.data.debug)) { 14 | debug.flip() 15 | s.options.debug = debug.on 16 | } 17 | if (message.data.takerFee || message.data.makerFee) { 18 | s.exchange.initFees() 19 | } 20 | try { 21 | let newConfig = _.defaultsDeep({ modified: message.data }, s.options) 22 | // let filename = s.options.strategy.name + "_" + s.options.period + "_" + (new Date().getTime()) 23 | var target = require('path').resolve(__dirname, '../../../' + s.options.conf) 24 | require('fs').writeFileSync(target, JSON.stringify(newConfig, null, 2)) 25 | var target2 = require('path').resolve(__dirname, '../../../data/config/last_config.json') 26 | require('fs').writeFileSync(target2, JSON.stringify(newConfig, null, 2)) 27 | // console.log('wrote config', target) 28 | if (message.restart) { 29 | console.log('\nSome Core Param changed .should restart process...'.orange) 30 | var target3 = require('path').resolve(__dirname, '../../../data/pm2/restart_' + s.options.exchange + "_" + (s.options.name || '') + '.json') 31 | require('fs').writeFileSync(target3, JSON.stringify({ event: 'updateConfig', time: moment().format('MMDD HH:mm:ss') }, null, 2)) 32 | } 33 | } catch (e) { 34 | console.log('updateConfig error', e) 35 | } 36 | let data = { 37 | action: message.action, 38 | data: s.options, 39 | toast: 'trade.' + message.action + 'Ok' 40 | } 41 | if (cb) cb(data) 42 | } 43 | const updateSymbolFuture = (message, cb, s) => { 44 | if (message.data.type === 'marginMode') { 45 | s.exchange.updateMarginMode({ 46 | marginType: message.data.value, 47 | product_id: message.symbol 48 | }, (err) => { 49 | if (err) return 50 | let data = { 51 | action: message.action, 52 | toast: 'trade.' + message.action + 'Ok' 53 | } 54 | if (cb) cb(data) 55 | }) 56 | } else if (message.data.type === 'leverage') { 57 | s.exchange.updateLeverage({ 58 | leverage: message.data.value, 59 | product_id: message.symbol 60 | }, (err) => { 61 | if (err) return 62 | let data = { 63 | action: message.action, 64 | toast: 'trade.' + message.action + 'Ok' 65 | } 66 | if (cb) cb(data) 67 | }) 68 | } 69 | } 70 | 71 | 72 | module.exports = { 73 | updateConfig, 74 | updateSymbolFuture 75 | } -------------------------------------------------------------------------------- /extensions/xcoin/panacea/api/market.js: -------------------------------------------------------------------------------- 1 | var coreFactory = require('../../../../lib/core') 2 | /** 3 | * get exchagne all products 4 | * @param {*} message 5 | * @param {*} cb 6 | * @param {*} s 7 | */ 8 | const getProducts = (message, cb, s, conf, engine) => { 9 | let core = coreFactory(s, conf, engine) 10 | let pData = core.getExchangeProducts(s.options.exchange, 'USDT', 'detail') 11 | let data = { 12 | action: message.action, 13 | data: pData[0].products 14 | } 15 | if (cb) cb(data) 16 | } 17 | /** 18 | * get exchange symbols real-time price 19 | * @param {*} message 20 | * @param {*} cb 21 | * @param {*} s 22 | */ 23 | const getTickers = (message, cb, s) => { 24 | s.exchange.getTickers(message.data, (err, realTickers) => { 25 | if (realTickers) { 26 | let tickers = Object.keys(realTickers).map(t => { 27 | return { 28 | symbol: realTickers[t].symbol, 29 | price: realTickers[t].close, 30 | percentage: realTickers[t].percentage, 31 | } 32 | }) 33 | let data = { 34 | action: message.action, 35 | data: tickers 36 | } 37 | if (cb) cb(data) 38 | } 39 | }) 40 | } 41 | /** 42 | * get exchange hot products 43 | * @param {} message 44 | * @param {*} cb 45 | */ 46 | const getPickerNormal = (message, cb, s) => { 47 | let data = { 48 | action: message.action, 49 | data: require(`../../../../data/exchanges/${s.options.exchange}_hot_products.json`) 50 | } 51 | if (cb) cb(data) 52 | } 53 | /** 54 | * get exchange symbol klines 55 | * @param {*} message 56 | * @param {*} cb 57 | * @param {*} s 58 | */ 59 | const getKlines = (message, cb, s) => { 60 | s.exchange.getKLines(message.data, (err, klines) => { 61 | if (err) { 62 | return 63 | } 64 | let data = { 65 | action: message.action, 66 | data: { 67 | period: message.data.period, 68 | klines 69 | } 70 | } 71 | if (cb) cb(data) 72 | }) 73 | } 74 | module.exports = { 75 | getKlines, 76 | getProducts, 77 | getPickerNormal, 78 | getTickers 79 | } -------------------------------------------------------------------------------- /extensions/xcoin/panacea/api/operation.js: -------------------------------------------------------------------------------- 1 | 2 | var coreFactory = require('../../../../lib/core') 3 | , { getInitData } = require('./status') 4 | , _ = require('lodash') 5 | 6 | , moment = require('moment') 7 | , debug = require('../../../../lib/debug') 8 | , helpers = require('../../../../lib/helpers') 9 | /**dynamic update watch list group */ 10 | const addSymbol = (message, cb, s, conf, engine) => { 11 | let shouldAddSymbols = message.symbols.filter(m => s.options.symbols.every(p => p.normalized !== m)) 12 | if (!shouldAddSymbols.length) return 13 | let symbols = shouldAddSymbols.map(p => helpers.objectifySelector(p)) 14 | engine.initSymbols(symbols) 15 | var core = coreFactory(s, conf, engine) 16 | core.getInitKLines(() => { 17 | s.options.symbols.push(...symbols) 18 | if (s.options.symbols && s.options.symbols.length) { 19 | let i = 1 20 | s.options.symbols.forEach(symbol => { 21 | if (s.symbols[symbol.product_id]) { 22 | s.symbols[symbol.product_id].index = i 23 | i++ 24 | } 25 | }) 26 | let data = { 27 | action: 'init', 28 | data: getInitData(s) 29 | } 30 | if (cb) cb(data) 31 | data = { 32 | action: message.action, 33 | toast: 'trade.' + message.action + 'Ok', 34 | data: { 35 | success: true, 36 | buy: message.data.buy 37 | } 38 | } 39 | if (cb) cb(data) 40 | 41 | } 42 | }, JSON.parse(JSON.stringify(symbols)), { 43 | limit: s.options.min_periods 44 | }) 45 | } 46 | const removeAllSymbol = (message, cb, s) => { 47 | while (s.options.symbols.length > 1) { 48 | let symbol = s.options.symbols.pop() 49 | delete s.symbols[symbol.product_id] 50 | } 51 | let data = { 52 | action: 'init', 53 | data: getInitData(s) 54 | } 55 | if (cb) cb(data) 56 | data = { 57 | action: message.action, 58 | toast: 'trade.' + message.action + 'Ok' 59 | } 60 | if (cb) cb(data) 61 | } 62 | const removeSymbol = (message, cb, s) => { 63 | let find = s.options.symbols.find(s => s.normalized === message.symbol) 64 | if (find) { 65 | let index = s.options.symbols.indexOf(find) 66 | s.options.symbols.splice(index, 1) 67 | delete s.symbols[find.product_id] 68 | let i = 1 69 | s.options.symbols.forEach(symbol => { 70 | if (s.symbols[symbol.product_id]) { 71 | s.symbols[symbol.product_id].index = i 72 | i++ 73 | } 74 | }) 75 | let data = { 76 | action: 'init', 77 | data: getInitData(s) 78 | } 79 | if (cb) cb(data) 80 | data = { 81 | action: message.action, 82 | toast: 'trade.' + message.action + 'Ok' 83 | } 84 | if (cb) cb(data) 85 | } 86 | } 87 | /** bot group */ 88 | const getDemoBot = (message, cb) => { 89 | let data = { 90 | action: message.action, 91 | data: [{ 92 | "name": "demoName", 93 | "des": "demoDes", 94 | "protocol": "ws", 95 | "host": "43.153.178.133", 96 | "port": "17832", 97 | "id": "bot-demo", 98 | "type": "xcoin", 99 | "isDemo": true 100 | }] 101 | } 102 | if (cb) cb(data) 103 | } 104 | const getBalance = (message, cb) => { 105 | s.exchange.getBalance({ 106 | position_side: "LONG", 107 | currency: message.data.currency || s.options.symbols[0].currency, 108 | asset: message.data.asset || s.options.symbols[0].asset 109 | }, (err, balance) => { 110 | if (err) { 111 | return 112 | } 113 | if (s.options.future) { 114 | s.exchange.getBalance({ 115 | position_side: "SHORT", 116 | currency: message.data.currency || 'BTC', 117 | asset: message.data.asset || 'USDt' 118 | }, (err, shortBalance) => { 119 | if (err) { 120 | return 121 | } 122 | let data = { 123 | balance, 124 | shortBalance 125 | } 126 | if (cb) cb(data) 127 | return 128 | }) 129 | } 130 | else { 131 | let data = { 132 | balance 133 | } 134 | if (cb) cb(data) 135 | return 136 | } 137 | }) 138 | } 139 | /** buy sell group */ 140 | const buy = (message, cb, s, conf, engine) => { 141 | let find = s.options.symbols.find(s => s.product_id === message.symbol) 142 | if (find) { 143 | var core = coreFactory(s, conf, engine) 144 | core.buy(() => { 145 | let data = { 146 | action: message.action, 147 | toast: 'trade.' + message.action + 'Ok' 148 | } 149 | if (cb) cb(data) 150 | }, find, message.data.position_side, message.data.size) 151 | } 152 | } 153 | /** buy sell group */ 154 | const sell = (message, cb, s, conf, engine) => { 155 | let find = s.options.symbols.find(s => s.product_id === message.symbol) 156 | if (find) { 157 | var core = coreFactory(s, conf, engine) 158 | core.sell(() => { 159 | let data = { 160 | action: message.action, 161 | toast: 'trade.' + message.action + 'Ok' 162 | } 163 | if (cb) cb(data) 164 | }, find, message.data.position_side, message.data.size) 165 | } 166 | } 167 | const sellAll = (message, cb, s, conf, engine) => { 168 | let boughtSymbols = s.options.symbols.filter((ss) => { 169 | // console.log('realTickers', s.normalized, realTickers[t].normalized, s.normalized === realTickers[t].normalized) 170 | if (s.symbols[ss.product_id] && s.symbols[ss.product_id].action && (s.symbols[ss.product_id].action === 'bought' || s.symbols[ss.product_id].action === 'partSell')) { 171 | return true 172 | } 173 | return false 174 | }) 175 | var core = coreFactory(s, conf, engine) 176 | core.sellAll(() => { 177 | let data = { 178 | action: message.action, 179 | toast: 'trade.' + message.action + 'Ok' 180 | } 181 | if (cb) cb(data) 182 | }, boughtSymbols) 183 | } 184 | 185 | module.exports = { 186 | addSymbol, 187 | removeAllSymbol, 188 | removeSymbol, 189 | buy, 190 | sell, 191 | sellAll, 192 | getDemoBot, 193 | getBalance 194 | } -------------------------------------------------------------------------------- /extensions/xcoin/panacea/api/panacea.js: -------------------------------------------------------------------------------- 1 | const checkVersion = (message, cb) => { 2 | let versionObj = require('../../../../data/panacea/version.json') 3 | function versionCompare(oldVer, newVer) { 4 | let v1s = oldVer.split('.') 5 | let v2s = newVer.split('.') 6 | let oldV = 10000 * v1s[0] + 100 * v1s[1] + parseInt(v1s[2]) 7 | let newV = 10000 * v2s[0] + 100 * v2s[1] + parseInt(v2s[2]) 8 | return newV > oldV 9 | } 10 | let hasNewVersion = versionCompare(message.data.version, versionObj.version) 11 | if (!hasNewVersion) return 12 | let data = { 13 | action: message.action, 14 | data: versionObj 15 | } 16 | if (cb) cb(data) 17 | } 18 | module.exports = { 19 | checkVersion 20 | } -------------------------------------------------------------------------------- /extensions/xcoin/panacea/api/status.js: -------------------------------------------------------------------------------- 1 | var config = require("../../../../config/config-structure.json") 2 | /** 3 | * get real-time symbols data 4 | * @param {*} s 5 | * @returns 6 | */ 7 | const getRefreshData = (s) => { 8 | let symbols = getSymbols(s, false) 9 | let output = { 10 | symbols, 11 | status: s.status 12 | } 13 | return output 14 | } 15 | /** 16 | * get bot init status with full symbols data and other data 17 | * @param {*} s 18 | * @returns 19 | */ 20 | const getInitData = (s) => { 21 | let symbols = getSymbols(s, true) 22 | let output = { 23 | strategies: s.strategies, // all strategies list 24 | exchange: s.exchange, // bot exchange info 25 | symbols, // symbols status data 26 | options: s.options, // bot config params 27 | status: s.status, // bot status, 28 | config: config 29 | } 30 | return output 31 | } 32 | /** 33 | * get data to save to database 34 | */ 35 | const getBacktestData = (s) => { 36 | let symbols = getSymbols(s, true) 37 | let output = { 38 | symbols, 39 | options: s.options, 40 | status: s.status 41 | } 42 | return output 43 | } 44 | /** 45 | * get all symbols status 46 | * @param {} s 47 | * @param {*} init //if in init mode 48 | * @returns 49 | */ 50 | const getSymbols = (s, init = false) => { 51 | return Object.keys(s.symbols).map(key => { 52 | const symbol = s.symbols[key] 53 | let output = { 54 | product_id: symbol.product_id, 55 | price: (symbol.period && symbol.period.close) || '', 56 | normalized: symbol.normalized, 57 | min_size: symbol.min_size, 58 | asset: symbol.asset, 59 | currency: symbol.currency, 60 | assetCaptial: symbol.asset_amount, 61 | leverage: symbol.leverage, 62 | isolated: symbol.isolated, 63 | usdtProfit: symbol.usdtProfit, 64 | dynamicProfit: symbol.dynamicProfit, 65 | dynamicUsdtProfit: symbol.dynamicUsdtProfit, 66 | profit: symbol.profit, 67 | signal: symbol.signal, 68 | win: symbol.win, 69 | lost: symbol.lost, 70 | winLostRate: symbol.winLostRate, 71 | action: symbol.buy_order ? 'buying' : (symbol.sell_order ? 'selling' : symbol.action), 72 | inSignal: symbol.inSignal, 73 | trades: symbol.my_trades, 74 | lastTradeTime: symbol.last_trade_time 75 | } 76 | if (init) { 77 | output.klines = symbol.lookback.map(p => { 78 | return p 79 | }).reverse() 80 | } 81 | else { 82 | output.kline = symbol.period 83 | // console.log(symbol.product_id, symbol.period.close, symbol.period.strategy) 84 | } 85 | /// console.log('output', output) 86 | // console.timeEnd('getSymbolData') 87 | return output 88 | }) 89 | } 90 | module.exports = { 91 | getRefreshData, 92 | getInitData, 93 | getBacktestData 94 | } -------------------------------------------------------------------------------- /extensions/xcoin/panacea/api/strategy.js: -------------------------------------------------------------------------------- 1 | module.exports = {} -------------------------------------------------------------------------------- /extensions/xcoin/panacea/index.js: -------------------------------------------------------------------------------- 1 | const webSocket = require('ws') 2 | , random_port = require('random-port') 3 | , helpers = require('../../../lib/helpers') 4 | , debug = require('../../../lib/debug') 5 | , apiFactory = require('./api/api') 6 | module.exports = function panacea(s, conf, engine, keyboard) { 7 | let aliveCount = 0 8 | let api = apiFactory() 9 | var wsServer = { 10 | wss: null, 11 | run: function () { 12 | if (!s.options.output.panacea.port || s.options.output.panacea.port === 0) { 13 | random_port({ from: 17000, range: 1000 }, function (port) { 14 | this.startServer(s.options.output.panacea.ip, port) 15 | }) 16 | } else { 17 | this.startServer(s.options.output.panacea.ip, s.options.output.panacea.port) 18 | } 19 | }, 20 | reply: function (ws, data) { 21 | debug.msg('reply ' + data.action + " " + JSON.stringify(data).length) 22 | ws.send(JSON.stringify(data)) 23 | }, 24 | startServer: function (ip, port) { 25 | var self = this 26 | this.wss = new webSocket.Server({ host: ip, port: port }) 27 | const interval = setInterval(() => { 28 | this.wss.clients.forEach(function each(ws) { 29 | if (ws.isAlive === false) { 30 | aliveCount-- 31 | return ws.terminate(); 32 | } 33 | ws.isAlive = false; 34 | ws.ping(); 35 | }); 36 | }, 60000); 37 | this.wss.on('close', function close() { 38 | clearInterval(interval); 39 | }); 40 | console.log('WebSocket running on ws://%s:%s'.green, ip, port) 41 | this.wss.on('connection', (ws) => { 42 | aliveCount++ 43 | ws.isAlive = true; 44 | debug.msg('Websocket new client join '.cyan + aliveCount.toString().cyan) 45 | this.init(ws) 46 | ws.on('pong', () => { 47 | ws.isAlive = true 48 | }); 49 | ws.on('message', (data) => { 50 | try { 51 | let message = JSON.parse(data) 52 | debug.msg('receive message ' + message.action) 53 | /** client user auth */ 54 | if (message.action !== 'getTickers' && message.action !== 'checkVersion' && message.action !== 'getProducts' && message.action !== 'getPickerNormal') { 55 | if (!message.apiKey || message.apiKey !== conf.secret.keys.apiKey) { 56 | self.reply(ws, { 57 | action: 'none', 58 | toast: 'bot.apiKeyError' 59 | }) 60 | return 61 | } 62 | } 63 | switch (message.action) { 64 | case 'init': 65 | self.init() 66 | break; 67 | case "refresh": 68 | self.refresh() 69 | break; 70 | default: 71 | api[message.action](message, (data) => { 72 | self.reply(ws, data) 73 | }, s, conf, engine, keyboard) 74 | break 75 | } 76 | } catch (e) { 77 | self.reply(ws, { 78 | action: 'error', 79 | data: e.toString() 80 | }) 81 | console.log('error', e) 82 | } 83 | }) 84 | 85 | }) 86 | }, 87 | /** 88 | * init all bot status 89 | * @param {} ws 90 | */ 91 | async init(ws) { 92 | if (s.status.status === 'created') { 93 | let data = { 94 | action: 'ready' 95 | } 96 | this.reply(ws, data) 97 | while (s.status.status !== 'ready') { 98 | await helpers.sleep(3000) 99 | } 100 | } 101 | data = { 102 | action: 'init', 103 | data: api.getInitData(s) 104 | } 105 | this.reply(ws, data) 106 | s.status.status = 'work' 107 | }, 108 | /** 109 | * broadcast all symbols real-time data to all client 110 | * @returns 111 | */ 112 | refresh: function () { 113 | if (!this.wss) return 114 | if (s.status.status !== 'work') return 115 | this.wss.clients.forEach(client => { 116 | if (client.readyState === 1) { 117 | let data = { 118 | action: 'refresh', 119 | data: api.getRefreshData(s) 120 | } 121 | this.reply(client, data) 122 | } 123 | }) 124 | } 125 | } 126 | return wsServer 127 | } 128 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "panacea-api", 3 | "version": "1.2.7", 4 | "description": "Api for Panacea", 5 | "bugs": "https://github.com/markmind/panacea-api/issues", 6 | "license": "MIT", 7 | "repository": { 8 | "type": "git", 9 | "url": "https://github.com/markmind/panacea-api.git" 10 | }, 11 | "scripts": { 12 | "docs:dev": "vitepress dev docs", 13 | "docs:build": "vitepress build docs", 14 | "docs:serve": "vitepress serve docs" 15 | }, 16 | "devDependencies": { 17 | "vitepress": "^1.0.0-alpha.65", 18 | "yargs": "^16.1.1" 19 | }, 20 | "engines": { 21 | "node": ">=16.0.0" 22 | }, 23 | "snyk": true 24 | } -------------------------------------------------------------------------------- /yarn.lock: -------------------------------------------------------------------------------- 1 | # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. 2 | # yarn lockfile v1 3 | 4 | 5 | "@algolia/autocomplete-core@1.7.4": 6 | version "1.7.4" 7 | resolved "https://registry.npmmirror.com/@algolia/autocomplete-core/-/autocomplete-core-1.7.4.tgz#85ff36b2673654a393c8c505345eaedd6eaa4f70" 8 | integrity sha512-daoLpQ3ps/VTMRZDEBfU8ixXd+amZcNJ4QSP3IERGyzqnL5Ch8uSRFt/4G8pUvW9c3o6GA4vtVv4I4lmnkdXyg== 9 | dependencies: 10 | "@algolia/autocomplete-shared" "1.7.4" 11 | 12 | "@algolia/autocomplete-preset-algolia@1.7.4": 13 | version "1.7.4" 14 | resolved "https://registry.npmmirror.com/@algolia/autocomplete-preset-algolia/-/autocomplete-preset-algolia-1.7.4.tgz#610ee1d887962f230b987cba2fd6556478000bc3" 15 | integrity sha512-s37hrvLEIfcmKY8VU9LsAXgm2yfmkdHT3DnA3SgHaY93yjZ2qL57wzb5QweVkYuEBZkT2PIREvRoLXC2sxTbpQ== 16 | dependencies: 17 | "@algolia/autocomplete-shared" "1.7.4" 18 | 19 | "@algolia/autocomplete-shared@1.7.4": 20 | version "1.7.4" 21 | resolved "https://registry.npmmirror.com/@algolia/autocomplete-shared/-/autocomplete-shared-1.7.4.tgz#78aea1140a50c4d193e1f06a13b7f12c5e2cbeea" 22 | integrity sha512-2VGCk7I9tA9Ge73Km99+Qg87w0wzW4tgUruvWAn/gfey1ZXgmxZtyIRBebk35R1O8TbK77wujVtCnpsGpRy1kg== 23 | 24 | "@algolia/cache-browser-local-storage@4.17.0": 25 | version "4.17.0" 26 | resolved "https://registry.npmmirror.com/@algolia/cache-browser-local-storage/-/cache-browser-local-storage-4.17.0.tgz#4c54a9b1795dcc1cd9f9533144f7df3057984d39" 27 | integrity sha512-myRSRZDIMYB8uCkO+lb40YKiYHi0fjpWRtJpR/dgkaiBlSD0plRyB6lLOh1XIfmMcSeBOqDE7y9m8xZMrXYfyQ== 28 | dependencies: 29 | "@algolia/cache-common" "4.17.0" 30 | 31 | "@algolia/cache-common@4.17.0": 32 | version "4.17.0" 33 | resolved "https://registry.npmmirror.com/@algolia/cache-common/-/cache-common-4.17.0.tgz#bc3da15548df585b44d76c55e66b0056a2b3f917" 34 | integrity sha512-g8mXzkrcUBIPZaulAuqE7xyHhLAYAcF2xSch7d9dABheybaU3U91LjBX6eJTEB7XVhEsgK4Smi27vWtAJRhIKQ== 35 | 36 | "@algolia/cache-in-memory@4.17.0": 37 | version "4.17.0" 38 | resolved "https://registry.npmmirror.com/@algolia/cache-in-memory/-/cache-in-memory-4.17.0.tgz#eb55a92cb8eb8641903a2b23fd6d05ebdaca2010" 39 | integrity sha512-PT32ciC/xI8z919d0oknWVu3kMfTlhQn3MKxDln3pkn+yA7F7xrxSALysxquv+MhFfNAcrtQ/oVvQVBAQSHtdw== 40 | dependencies: 41 | "@algolia/cache-common" "4.17.0" 42 | 43 | "@algolia/client-account@4.17.0": 44 | version "4.17.0" 45 | resolved "https://registry.npmmirror.com/@algolia/client-account/-/client-account-4.17.0.tgz#4b13e5a8e50a06be1f3289d9db337096ebc66b73" 46 | integrity sha512-sSEHx9GA6m7wrlsSMNBGfyzlIfDT2fkz2u7jqfCCd6JEEwmxt8emGmxAU/0qBfbhRSuGvzojoLJlr83BSZAKjA== 47 | dependencies: 48 | "@algolia/client-common" "4.17.0" 49 | "@algolia/client-search" "4.17.0" 50 | "@algolia/transporter" "4.17.0" 51 | 52 | "@algolia/client-analytics@4.17.0": 53 | version "4.17.0" 54 | resolved "https://registry.npmmirror.com/@algolia/client-analytics/-/client-analytics-4.17.0.tgz#1b36ffbe913b7b4d8900bc15982ca431f47a473c" 55 | integrity sha512-84ooP8QA3mQ958hQ9wozk7hFUbAO+81CX1CjAuerxBqjKIInh1fOhXKTaku05O/GHBvcfExpPLIQuSuLYziBXQ== 56 | dependencies: 57 | "@algolia/client-common" "4.17.0" 58 | "@algolia/client-search" "4.17.0" 59 | "@algolia/requester-common" "4.17.0" 60 | "@algolia/transporter" "4.17.0" 61 | 62 | "@algolia/client-common@4.17.0": 63 | version "4.17.0" 64 | resolved "https://registry.npmmirror.com/@algolia/client-common/-/client-common-4.17.0.tgz#67fd898006e3ac359ea3e3ed61abfc26147ffa53" 65 | integrity sha512-jHMks0ZFicf8nRDn6ma8DNNsdwGgP/NKiAAL9z6rS7CymJ7L0+QqTJl3rYxRW7TmBhsUH40wqzmrG6aMIN/DrQ== 66 | dependencies: 67 | "@algolia/requester-common" "4.17.0" 68 | "@algolia/transporter" "4.17.0" 69 | 70 | "@algolia/client-personalization@4.17.0": 71 | version "4.17.0" 72 | resolved "https://registry.npmmirror.com/@algolia/client-personalization/-/client-personalization-4.17.0.tgz#428d9f4762c22856b6062bb54351eb31834db6c1" 73 | integrity sha512-RMzN4dZLIta1YuwT7QC9o+OeGz2cU6eTOlGNE/6RcUBLOU3l9tkCOdln5dPE2jp8GZXPl2yk54b2nSs1+pAjqw== 74 | dependencies: 75 | "@algolia/client-common" "4.17.0" 76 | "@algolia/requester-common" "4.17.0" 77 | "@algolia/transporter" "4.17.0" 78 | 79 | "@algolia/client-search@4.17.0": 80 | version "4.17.0" 81 | resolved "https://registry.npmmirror.com/@algolia/client-search/-/client-search-4.17.0.tgz#0053c682f5f588e006c20791c27e8bcb0aa5b53c" 82 | integrity sha512-x4P2wKrrRIXszT8gb7eWsMHNNHAJs0wE7/uqbufm4tZenAp+hwU/hq5KVsY50v+PfwM0LcDwwn/1DroujsTFoA== 83 | dependencies: 84 | "@algolia/client-common" "4.17.0" 85 | "@algolia/requester-common" "4.17.0" 86 | "@algolia/transporter" "4.17.0" 87 | 88 | "@algolia/logger-common@4.17.0": 89 | version "4.17.0" 90 | resolved "https://registry.npmmirror.com/@algolia/logger-common/-/logger-common-4.17.0.tgz#0fcea39c9485554edb4cdbfd965c5748b0b837ac" 91 | integrity sha512-DGuoZqpTmIKJFDeyAJ7M8E/LOenIjWiOsg1XJ1OqAU/eofp49JfqXxbfgctlVZVmDABIyOz8LqEoJ6ZP4DTyvw== 92 | 93 | "@algolia/logger-console@4.17.0": 94 | version "4.17.0" 95 | resolved "https://registry.npmmirror.com/@algolia/logger-console/-/logger-console-4.17.0.tgz#8ac56ef4259c4fa3eb9eb6586c7b4b4ed942e8da" 96 | integrity sha512-zMPvugQV/gbXUvWBCzihw6m7oxIKp48w37QBIUu/XqQQfxhjoOE9xyfJr1KldUt5FrYOKZJVsJaEjTsu+bIgQg== 97 | dependencies: 98 | "@algolia/logger-common" "4.17.0" 99 | 100 | "@algolia/requester-browser-xhr@4.17.0": 101 | version "4.17.0" 102 | resolved "https://registry.npmmirror.com/@algolia/requester-browser-xhr/-/requester-browser-xhr-4.17.0.tgz#f52fdeeac2f3c531f00838920af33a73066a159b" 103 | integrity sha512-aSOX/smauyTkP21Pf52pJ1O2LmNFJ5iHRIzEeTh0mwBeADO4GdG94cAWDILFA9rNblq/nK3EDh3+UyHHjplZ1A== 104 | dependencies: 105 | "@algolia/requester-common" "4.17.0" 106 | 107 | "@algolia/requester-common@4.17.0": 108 | version "4.17.0" 109 | resolved "https://registry.npmmirror.com/@algolia/requester-common/-/requester-common-4.17.0.tgz#746020d2cbc829213e7cede8eef2182c7a71e32b" 110 | integrity sha512-XJjmWFEUlHu0ijvcHBoixuXfEoiRUdyzQM6YwTuB8usJNIgShua8ouFlRWF8iCeag0vZZiUm4S2WCVBPkdxFgg== 111 | 112 | "@algolia/requester-node-http@4.17.0": 113 | version "4.17.0" 114 | resolved "https://registry.npmmirror.com/@algolia/requester-node-http/-/requester-node-http-4.17.0.tgz#262276d94c25a4ec2128b1bdfb9471529528d8b9" 115 | integrity sha512-bpb/wDA1aC6WxxM8v7TsFspB7yBN3nqCGs2H1OADolQR/hiAIjAxusbuMxVbRFOdaUvAIqioIIkWvZdpYNIn8w== 116 | dependencies: 117 | "@algolia/requester-common" "4.17.0" 118 | 119 | "@algolia/transporter@4.17.0": 120 | version "4.17.0" 121 | resolved "https://registry.npmmirror.com/@algolia/transporter/-/transporter-4.17.0.tgz#6aabdbc20c475d72d83c8e6519f1191f1a51fb37" 122 | integrity sha512-6xL6H6fe+Fi0AEP3ziSgC+G04RK37iRb4uUUqVAH9WPYFI8g+LYFq6iv5HS8Cbuc5TTut+Bwj6G+dh/asdb9uA== 123 | dependencies: 124 | "@algolia/cache-common" "4.17.0" 125 | "@algolia/logger-common" "4.17.0" 126 | "@algolia/requester-common" "4.17.0" 127 | 128 | "@babel/parser@^7.16.4": 129 | version "7.21.4" 130 | resolved "https://registry.npmmirror.com/@babel/parser/-/parser-7.21.4.tgz#94003fdfc520bbe2875d4ae557b43ddb6d880f17" 131 | integrity sha512-alVJj7k7zIxqBZ7BTRhz0IqJFxW1VJbm6N8JbcYhQ186df9ZBPbZBmWSqAMXwHGsCJdYks7z/voa3ibiS5bCIw== 132 | 133 | "@docsearch/css@3.3.3", "@docsearch/css@^3.3.3": 134 | version "3.3.3" 135 | resolved "https://registry.npmmirror.com/@docsearch/css/-/css-3.3.3.tgz#f9346c9e24602218341f51b8ba91eb9109add434" 136 | integrity sha512-6SCwI7P8ao+se1TUsdZ7B4XzL+gqeQZnBc+2EONZlcVa0dVrk0NjETxozFKgMv0eEGH8QzP1fkN+A1rH61l4eg== 137 | 138 | "@docsearch/js@^3.3.3": 139 | version "3.3.3" 140 | resolved "https://registry.npmmirror.com/@docsearch/js/-/js-3.3.3.tgz#70725a7a8fe92d221fcf0593263b936389d3728f" 141 | integrity sha512-2xAv2GFuHzzmG0SSZgf8wHX0qZX8n9Y1ZirKUk5Wrdc+vH9CL837x2hZIUdwcPZI9caBA+/CzxsS68O4waYjUQ== 142 | dependencies: 143 | "@docsearch/react" "3.3.3" 144 | preact "^10.0.0" 145 | 146 | "@docsearch/react@3.3.3": 147 | version "3.3.3" 148 | resolved "https://registry.npmmirror.com/@docsearch/react/-/react-3.3.3.tgz#907b6936a565f880b4c0892624b4f7a9f132d298" 149 | integrity sha512-pLa0cxnl+G0FuIDuYlW+EBK6Rw2jwLw9B1RHIeS4N4s2VhsfJ/wzeCi3CWcs5yVfxLd5ZK50t//TMA5e79YT7Q== 150 | dependencies: 151 | "@algolia/autocomplete-core" "1.7.4" 152 | "@algolia/autocomplete-preset-algolia" "1.7.4" 153 | "@docsearch/css" "3.3.3" 154 | algoliasearch "^4.0.0" 155 | 156 | "@esbuild/android-arm64@0.17.15": 157 | version "0.17.15" 158 | resolved "https://registry.npmmirror.com/@esbuild/android-arm64/-/android-arm64-0.17.15.tgz#893ad71f3920ccb919e1757c387756a9bca2ef42" 159 | integrity sha512-0kOB6Y7Br3KDVgHeg8PRcvfLkq+AccreK///B4Z6fNZGr/tNHX0z2VywCc7PTeWp+bPvjA5WMvNXltHw5QjAIA== 160 | 161 | "@esbuild/android-arm@0.17.15": 162 | version "0.17.15" 163 | resolved "https://registry.npmmirror.com/@esbuild/android-arm/-/android-arm-0.17.15.tgz#143e0d4e4c08c786ea410b9a7739779a9a1315d8" 164 | integrity sha512-sRSOVlLawAktpMvDyJIkdLI/c/kdRTOqo8t6ImVxg8yT7LQDUYV5Rp2FKeEosLr6ZCja9UjYAzyRSxGteSJPYg== 165 | 166 | "@esbuild/android-x64@0.17.15": 167 | version "0.17.15" 168 | resolved "https://registry.npmmirror.com/@esbuild/android-x64/-/android-x64-0.17.15.tgz#d2d12a7676b2589864281b2274355200916540bc" 169 | integrity sha512-MzDqnNajQZ63YkaUWVl9uuhcWyEyh69HGpMIrf+acR4otMkfLJ4sUCxqwbCyPGicE9dVlrysI3lMcDBjGiBBcQ== 170 | 171 | "@esbuild/darwin-arm64@0.17.15": 172 | version "0.17.15" 173 | resolved "https://registry.npmmirror.com/@esbuild/darwin-arm64/-/darwin-arm64-0.17.15.tgz#2e88e79f1d327a2a7d9d06397e5232eb0a473d61" 174 | integrity sha512-7siLjBc88Z4+6qkMDxPT2juf2e8SJxmsbNVKFY2ifWCDT72v5YJz9arlvBw5oB4W/e61H1+HDB/jnu8nNg0rLA== 175 | 176 | "@esbuild/darwin-x64@0.17.15": 177 | version "0.17.15" 178 | resolved "https://registry.npmmirror.com/@esbuild/darwin-x64/-/darwin-x64-0.17.15.tgz#9384e64c0be91388c57be6d3a5eaf1c32a99c91d" 179 | integrity sha512-NbImBas2rXwYI52BOKTW342Tm3LTeVlaOQ4QPZ7XuWNKiO226DisFk/RyPk3T0CKZkKMuU69yOvlapJEmax7cg== 180 | 181 | "@esbuild/freebsd-arm64@0.17.15": 182 | version "0.17.15" 183 | resolved "https://registry.npmmirror.com/@esbuild/freebsd-arm64/-/freebsd-arm64-0.17.15.tgz#2ad5a35bc52ebd9ca6b845dbc59ba39647a93c1a" 184 | integrity sha512-Xk9xMDjBVG6CfgoqlVczHAdJnCs0/oeFOspFap5NkYAmRCT2qTn1vJWA2f419iMtsHSLm+O8B6SLV/HlY5cYKg== 185 | 186 | "@esbuild/freebsd-x64@0.17.15": 187 | version "0.17.15" 188 | resolved "https://registry.npmmirror.com/@esbuild/freebsd-x64/-/freebsd-x64-0.17.15.tgz#b513a48446f96c75fda5bef470e64d342d4379cd" 189 | integrity sha512-3TWAnnEOdclvb2pnfsTWtdwthPfOz7qAfcwDLcfZyGJwm1SRZIMOeB5FODVhnM93mFSPsHB9b/PmxNNbSnd0RQ== 190 | 191 | "@esbuild/linux-arm64@0.17.15": 192 | version "0.17.15" 193 | resolved "https://registry.npmmirror.com/@esbuild/linux-arm64/-/linux-arm64-0.17.15.tgz#9697b168175bfd41fa9cc4a72dd0d48f24715f31" 194 | integrity sha512-T0MVnYw9KT6b83/SqyznTs/3Jg2ODWrZfNccg11XjDehIved2oQfrX/wVuev9N936BpMRaTR9I1J0tdGgUgpJA== 195 | 196 | "@esbuild/linux-arm@0.17.15": 197 | version "0.17.15" 198 | resolved "https://registry.npmmirror.com/@esbuild/linux-arm/-/linux-arm-0.17.15.tgz#5b22062c54f48cd92fab9ffd993732a52db70cd3" 199 | integrity sha512-MLTgiXWEMAMr8nmS9Gigx43zPRmEfeBfGCwxFQEMgJ5MC53QKajaclW6XDPjwJvhbebv+RzK05TQjvH3/aM4Xw== 200 | 201 | "@esbuild/linux-ia32@0.17.15": 202 | version "0.17.15" 203 | resolved "https://registry.npmmirror.com/@esbuild/linux-ia32/-/linux-ia32-0.17.15.tgz#eb28a13f9b60b5189fcc9e98e1024f6b657ba54c" 204 | integrity sha512-wp02sHs015T23zsQtU4Cj57WiteiuASHlD7rXjKUyAGYzlOKDAjqK6bk5dMi2QEl/KVOcsjwL36kD+WW7vJt8Q== 205 | 206 | "@esbuild/linux-loong64@0.17.15": 207 | version "0.17.15" 208 | resolved "https://registry.npmmirror.com/@esbuild/linux-loong64/-/linux-loong64-0.17.15.tgz#32454bdfe144cf74b77895a8ad21a15cb81cfbe5" 209 | integrity sha512-k7FsUJjGGSxwnBmMh8d7IbObWu+sF/qbwc+xKZkBe/lTAF16RqxRCnNHA7QTd3oS2AfGBAnHlXL67shV5bBThQ== 210 | 211 | "@esbuild/linux-mips64el@0.17.15": 212 | version "0.17.15" 213 | resolved "https://registry.npmmirror.com/@esbuild/linux-mips64el/-/linux-mips64el-0.17.15.tgz#af12bde0d775a318fad90eb13a0455229a63987c" 214 | integrity sha512-ZLWk6czDdog+Q9kE/Jfbilu24vEe/iW/Sj2d8EVsmiixQ1rM2RKH2n36qfxK4e8tVcaXkvuV3mU5zTZviE+NVQ== 215 | 216 | "@esbuild/linux-ppc64@0.17.15": 217 | version "0.17.15" 218 | resolved "https://registry.npmmirror.com/@esbuild/linux-ppc64/-/linux-ppc64-0.17.15.tgz#34c5ed145b2dfc493d3e652abac8bd3baa3865a5" 219 | integrity sha512-mY6dPkIRAiFHRsGfOYZC8Q9rmr8vOBZBme0/j15zFUKM99d4ILY4WpOC7i/LqoY+RE7KaMaSfvY8CqjJtuO4xg== 220 | 221 | "@esbuild/linux-riscv64@0.17.15": 222 | version "0.17.15" 223 | resolved "https://registry.npmmirror.com/@esbuild/linux-riscv64/-/linux-riscv64-0.17.15.tgz#87bd515e837f2eb004b45f9e6a94dc5b93f22b92" 224 | integrity sha512-EcyUtxffdDtWjjwIH8sKzpDRLcVtqANooMNASO59y+xmqqRYBBM7xVLQhqF7nksIbm2yHABptoioS9RAbVMWVA== 225 | 226 | "@esbuild/linux-s390x@0.17.15": 227 | version "0.17.15" 228 | resolved "https://registry.npmmirror.com/@esbuild/linux-s390x/-/linux-s390x-0.17.15.tgz#20bf7947197f199ddac2ec412029a414ceae3aa3" 229 | integrity sha512-BuS6Jx/ezxFuHxgsfvz7T4g4YlVrmCmg7UAwboeyNNg0OzNzKsIZXpr3Sb/ZREDXWgt48RO4UQRDBxJN3B9Rbg== 230 | 231 | "@esbuild/linux-x64@0.17.15": 232 | version "0.17.15" 233 | resolved "https://registry.npmmirror.com/@esbuild/linux-x64/-/linux-x64-0.17.15.tgz#31b93f9c94c195e852c20cd3d1914a68aa619124" 234 | integrity sha512-JsdS0EgEViwuKsw5tiJQo9UdQdUJYuB+Mf6HxtJSPN35vez1hlrNb1KajvKWF5Sa35j17+rW1ECEO9iNrIXbNg== 235 | 236 | "@esbuild/netbsd-x64@0.17.15": 237 | version "0.17.15" 238 | resolved "https://registry.npmmirror.com/@esbuild/netbsd-x64/-/netbsd-x64-0.17.15.tgz#8da299b3ac6875836ca8cdc1925826498069ac65" 239 | integrity sha512-R6fKjtUysYGym6uXf6qyNephVUQAGtf3n2RCsOST/neIwPqRWcnc3ogcielOd6pT+J0RDR1RGcy0ZY7d3uHVLA== 240 | 241 | "@esbuild/openbsd-x64@0.17.15": 242 | version "0.17.15" 243 | resolved "https://registry.npmmirror.com/@esbuild/openbsd-x64/-/openbsd-x64-0.17.15.tgz#04a1ec3d4e919714dba68dcf09eeb1228ad0d20c" 244 | integrity sha512-mVD4PGc26b8PI60QaPUltYKeSX0wxuy0AltC+WCTFwvKCq2+OgLP4+fFd+hZXzO2xW1HPKcytZBdjqL6FQFa7w== 245 | 246 | "@esbuild/sunos-x64@0.17.15": 247 | version "0.17.15" 248 | resolved "https://registry.npmmirror.com/@esbuild/sunos-x64/-/sunos-x64-0.17.15.tgz#6694ebe4e16e5cd7dab6505ff7c28f9c1c695ce5" 249 | integrity sha512-U6tYPovOkw3459t2CBwGcFYfFRjivcJJc1WC8Q3funIwX8x4fP+R6xL/QuTPNGOblbq/EUDxj9GU+dWKX0oWlQ== 250 | 251 | "@esbuild/win32-arm64@0.17.15": 252 | version "0.17.15" 253 | resolved "https://registry.npmmirror.com/@esbuild/win32-arm64/-/win32-arm64-0.17.15.tgz#1f95b2564193c8d1fee8f8129a0609728171d500" 254 | integrity sha512-W+Z5F++wgKAleDABemiyXVnzXgvRFs+GVKThSI+mGgleLWluv0D7Diz4oQpgdpNzh4i2nNDzQtWbjJiqutRp6Q== 255 | 256 | "@esbuild/win32-ia32@0.17.15": 257 | version "0.17.15" 258 | resolved "https://registry.npmmirror.com/@esbuild/win32-ia32/-/win32-ia32-0.17.15.tgz#c362b88b3df21916ed7bcf75c6d09c6bf3ae354a" 259 | integrity sha512-Muz/+uGgheShKGqSVS1KsHtCyEzcdOn/W/Xbh6H91Etm+wiIfwZaBn1W58MeGtfI8WA961YMHFYTthBdQs4t+w== 260 | 261 | "@esbuild/win32-x64@0.17.15": 262 | version "0.17.15" 263 | resolved "https://registry.npmmirror.com/@esbuild/win32-x64/-/win32-x64-0.17.15.tgz#c2e737f3a201ebff8e2ac2b8e9f246b397ad19b8" 264 | integrity sha512-DjDa9ywLUUmjhV2Y9wUTIF+1XsmuFGvZoCmOWkli1XcNAh5t25cc7fgsCx4Zi/Uurep3TTLyDiKATgGEg61pkA== 265 | 266 | "@types/web-bluetooth@^0.0.16": 267 | version "0.0.16" 268 | resolved "https://registry.npmmirror.com/@types/web-bluetooth/-/web-bluetooth-0.0.16.tgz#1d12873a8e49567371f2a75fe3e7f7edca6662d8" 269 | integrity sha512-oh8q2Zc32S6gd/j50GowEjKLoOVOwHP/bWVjKJInBwQqdOYMdPrf1oVlelTlyfFK3CKxL1uahMDAr+vy8T7yMQ== 270 | 271 | "@vitejs/plugin-vue@^4.1.0": 272 | version "4.1.0" 273 | resolved "https://registry.npmmirror.com/@vitejs/plugin-vue/-/plugin-vue-4.1.0.tgz#b6a9d83cd91575f7ee15593f6444397f68751073" 274 | integrity sha512-++9JOAFdcXI3lyer9UKUV4rfoQ3T1RN8yDqoCLar86s0xQct5yblxAE+yWgRnU5/0FOlVCpTZpYSBV/bGWrSrQ== 275 | 276 | "@vue/compiler-core@3.2.47": 277 | version "3.2.47" 278 | resolved "https://registry.npmmirror.com/@vue/compiler-core/-/compiler-core-3.2.47.tgz#3e07c684d74897ac9aa5922c520741f3029267f8" 279 | integrity sha512-p4D7FDnQb7+YJmO2iPEv0SQNeNzcbHdGByJDsT4lynf63AFkOTFN07HsiRSvjGo0QrxR/o3d0hUyNCUnBU2Tig== 280 | dependencies: 281 | "@babel/parser" "^7.16.4" 282 | "@vue/shared" "3.2.47" 283 | estree-walker "^2.0.2" 284 | source-map "^0.6.1" 285 | 286 | "@vue/compiler-dom@3.2.47": 287 | version "3.2.47" 288 | resolved "https://registry.npmmirror.com/@vue/compiler-dom/-/compiler-dom-3.2.47.tgz#a0b06caf7ef7056939e563dcaa9cbde30794f305" 289 | integrity sha512-dBBnEHEPoftUiS03a4ggEig74J2YBZ2UIeyfpcRM2tavgMWo4bsEfgCGsu+uJIL/vax9S+JztH8NmQerUo7shQ== 290 | dependencies: 291 | "@vue/compiler-core" "3.2.47" 292 | "@vue/shared" "3.2.47" 293 | 294 | "@vue/compiler-sfc@3.2.47": 295 | version "3.2.47" 296 | resolved "https://registry.npmmirror.com/@vue/compiler-sfc/-/compiler-sfc-3.2.47.tgz#1bdc36f6cdc1643f72e2c397eb1a398f5004ad3d" 297 | integrity sha512-rog05W+2IFfxjMcFw10tM9+f7i/+FFpZJJ5XHX72NP9eC2uRD+42M3pYcQqDXVYoj74kHMSEdQ/WmCjt8JFksQ== 298 | dependencies: 299 | "@babel/parser" "^7.16.4" 300 | "@vue/compiler-core" "3.2.47" 301 | "@vue/compiler-dom" "3.2.47" 302 | "@vue/compiler-ssr" "3.2.47" 303 | "@vue/reactivity-transform" "3.2.47" 304 | "@vue/shared" "3.2.47" 305 | estree-walker "^2.0.2" 306 | magic-string "^0.25.7" 307 | postcss "^8.1.10" 308 | source-map "^0.6.1" 309 | 310 | "@vue/compiler-ssr@3.2.47": 311 | version "3.2.47" 312 | resolved "https://registry.npmmirror.com/@vue/compiler-ssr/-/compiler-ssr-3.2.47.tgz#35872c01a273aac4d6070ab9d8da918ab13057ee" 313 | integrity sha512-wVXC+gszhulcMD8wpxMsqSOpvDZ6xKXSVWkf50Guf/S+28hTAXPDYRTbLQ3EDkOP5Xz/+SY37YiwDquKbJOgZw== 314 | dependencies: 315 | "@vue/compiler-dom" "3.2.47" 316 | "@vue/shared" "3.2.47" 317 | 318 | "@vue/devtools-api@^6.5.0": 319 | version "6.5.0" 320 | resolved "https://registry.npmmirror.com/@vue/devtools-api/-/devtools-api-6.5.0.tgz#98b99425edee70b4c992692628fa1ea2c1e57d07" 321 | integrity sha512-o9KfBeaBmCKl10usN4crU53fYtC1r7jJwdGKjPT24t348rHxgfpZ0xL3Xm/gLUYnc0oTp8LAmrxOeLyu6tbk2Q== 322 | 323 | "@vue/reactivity-transform@3.2.47": 324 | version "3.2.47" 325 | resolved "https://registry.npmmirror.com/@vue/reactivity-transform/-/reactivity-transform-3.2.47.tgz#e45df4d06370f8abf29081a16afd25cffba6d84e" 326 | integrity sha512-m8lGXw8rdnPVVIdIFhf0LeQ/ixyHkH5plYuS83yop5n7ggVJU+z5v0zecwEnX7fa7HNLBhh2qngJJkxpwEEmYA== 327 | dependencies: 328 | "@babel/parser" "^7.16.4" 329 | "@vue/compiler-core" "3.2.47" 330 | "@vue/shared" "3.2.47" 331 | estree-walker "^2.0.2" 332 | magic-string "^0.25.7" 333 | 334 | "@vue/reactivity@3.2.47": 335 | version "3.2.47" 336 | resolved "https://registry.npmmirror.com/@vue/reactivity/-/reactivity-3.2.47.tgz#1d6399074eadfc3ed35c727e2fd707d6881140b6" 337 | integrity sha512-7khqQ/75oyyg+N/e+iwV6lpy1f5wq759NdlS1fpAhFXa8VeAIKGgk2E/C4VF59lx5b+Ezs5fpp/5WsRYXQiKxQ== 338 | dependencies: 339 | "@vue/shared" "3.2.47" 340 | 341 | "@vue/runtime-core@3.2.47": 342 | version "3.2.47" 343 | resolved "https://registry.npmmirror.com/@vue/runtime-core/-/runtime-core-3.2.47.tgz#406ebade3d5551c00fc6409bbc1eeb10f32e121d" 344 | integrity sha512-RZxbLQIRB/K0ev0K9FXhNbBzT32H9iRtYbaXb0ZIz2usLms/D55dJR2t6cIEUn6vyhS3ALNvNthI+Q95C+NOpA== 345 | dependencies: 346 | "@vue/reactivity" "3.2.47" 347 | "@vue/shared" "3.2.47" 348 | 349 | "@vue/runtime-dom@3.2.47": 350 | version "3.2.47" 351 | resolved "https://registry.npmmirror.com/@vue/runtime-dom/-/runtime-dom-3.2.47.tgz#93e760eeaeab84dedfb7c3eaf3ed58d776299382" 352 | integrity sha512-ArXrFTjS6TsDei4qwNvgrdmHtD930KgSKGhS5M+j8QxXrDJYLqYw4RRcDy1bz1m1wMmb6j+zGLifdVHtkXA7gA== 353 | dependencies: 354 | "@vue/runtime-core" "3.2.47" 355 | "@vue/shared" "3.2.47" 356 | csstype "^2.6.8" 357 | 358 | "@vue/server-renderer@3.2.47": 359 | version "3.2.47" 360 | resolved "https://registry.npmmirror.com/@vue/server-renderer/-/server-renderer-3.2.47.tgz#8aa1d1871fc4eb5a7851aa7f741f8f700e6de3c0" 361 | integrity sha512-dN9gc1i8EvmP9RCzvneONXsKfBRgqFeFZLurmHOveL7oH6HiFXJw5OGu294n1nHc/HMgTy6LulU/tv5/A7f/LA== 362 | dependencies: 363 | "@vue/compiler-ssr" "3.2.47" 364 | "@vue/shared" "3.2.47" 365 | 366 | "@vue/shared@3.2.47": 367 | version "3.2.47" 368 | resolved "https://registry.npmmirror.com/@vue/shared/-/shared-3.2.47.tgz#e597ef75086c6e896ff5478a6bfc0a7aa4bbd14c" 369 | integrity sha512-BHGyyGN3Q97EZx0taMQ+OLNuZcW3d37ZEVmEAyeoA9ERdGvm9Irc/0Fua8SNyOtV1w6BS4q25wbMzJujO9HIfQ== 370 | 371 | "@vueuse/core@^9.13.0": 372 | version "9.13.0" 373 | resolved "https://registry.npmmirror.com/@vueuse/core/-/core-9.13.0.tgz#2f69e66d1905c1e4eebc249a01759cf88ea00cf4" 374 | integrity sha512-pujnclbeHWxxPRqXWmdkKV5OX4Wk4YeK7wusHqRwU0Q7EFusHoqNA/aPhB6KCh9hEqJkLAJo7bb0Lh9b+OIVzw== 375 | dependencies: 376 | "@types/web-bluetooth" "^0.0.16" 377 | "@vueuse/metadata" "9.13.0" 378 | "@vueuse/shared" "9.13.0" 379 | vue-demi "*" 380 | 381 | "@vueuse/metadata@9.13.0": 382 | version "9.13.0" 383 | resolved "https://registry.npmmirror.com/@vueuse/metadata/-/metadata-9.13.0.tgz#bc25a6cdad1b1a93c36ce30191124da6520539ff" 384 | integrity sha512-gdU7TKNAUVlXXLbaF+ZCfte8BjRJQWPCa2J55+7/h+yDtzw3vOoGQDRXzI6pyKyo6bXFT5/QoPE4hAknExjRLQ== 385 | 386 | "@vueuse/shared@9.13.0": 387 | version "9.13.0" 388 | resolved "https://registry.npmmirror.com/@vueuse/shared/-/shared-9.13.0.tgz#089ff4cc4e2e7a4015e57a8f32e4b39d096353b9" 389 | integrity sha512-UrnhU+Cnufu4S6JLCPZnkWh0WwZGUp72ktOF2DFptMlOs3TOdVv8xJN53zhHGARmVOsz5KqOls09+J1NR6sBKw== 390 | dependencies: 391 | vue-demi "*" 392 | 393 | algoliasearch@^4.0.0: 394 | version "4.17.0" 395 | resolved "https://registry.npmmirror.com/algoliasearch/-/algoliasearch-4.17.0.tgz#46ed58b2b99509d041f11cd1ea83623edf84355f" 396 | integrity sha512-JMRh2Mw6sEnVMiz6+APsi7lx9a2jiDFF+WUtANaUVCv6uSU9UOLdo5h9K3pdP6frRRybaM2fX8b1u0nqICS9aA== 397 | dependencies: 398 | "@algolia/cache-browser-local-storage" "4.17.0" 399 | "@algolia/cache-common" "4.17.0" 400 | "@algolia/cache-in-memory" "4.17.0" 401 | "@algolia/client-account" "4.17.0" 402 | "@algolia/client-analytics" "4.17.0" 403 | "@algolia/client-common" "4.17.0" 404 | "@algolia/client-personalization" "4.17.0" 405 | "@algolia/client-search" "4.17.0" 406 | "@algolia/logger-common" "4.17.0" 407 | "@algolia/logger-console" "4.17.0" 408 | "@algolia/requester-browser-xhr" "4.17.0" 409 | "@algolia/requester-common" "4.17.0" 410 | "@algolia/requester-node-http" "4.17.0" 411 | "@algolia/transporter" "4.17.0" 412 | 413 | ansi-regex@^5.0.1: 414 | version "5.0.1" 415 | resolved "https://registry.npmmirror.com/ansi-regex/-/ansi-regex-5.0.1.tgz#082cb2c89c9fe8659a311a53bd6a4dc5301db304" 416 | integrity sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ== 417 | 418 | ansi-sequence-parser@^1.1.0: 419 | version "1.1.0" 420 | resolved "https://registry.npmmirror.com/ansi-sequence-parser/-/ansi-sequence-parser-1.1.0.tgz#4d790f31236ac20366b23b3916b789e1bde39aed" 421 | integrity sha512-lEm8mt52to2fT8GhciPCGeCXACSz2UwIN4X2e2LJSnZ5uAbn2/dsYdOmUXq0AtWS5cpAupysIneExOgH0Vd2TQ== 422 | 423 | ansi-styles@^4.0.0: 424 | version "4.3.0" 425 | resolved "https://registry.npmmirror.com/ansi-styles/-/ansi-styles-4.3.0.tgz#edd803628ae71c04c85ae7a0906edad34b648937" 426 | integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg== 427 | dependencies: 428 | color-convert "^2.0.1" 429 | 430 | body-scroll-lock@4.0.0-beta.0: 431 | version "4.0.0-beta.0" 432 | resolved "https://registry.npmmirror.com/body-scroll-lock/-/body-scroll-lock-4.0.0-beta.0.tgz#4f78789d10e6388115c0460cd6d7d4dd2bbc4f7e" 433 | integrity sha512-a7tP5+0Mw3YlUJcGAKUqIBkYYGlYxk2fnCasq/FUph1hadxlTRjF+gAcZksxANnaMnALjxEddmSi/H3OR8ugcQ== 434 | 435 | cliui@^7.0.2: 436 | version "7.0.4" 437 | resolved "https://registry.npmmirror.com/cliui/-/cliui-7.0.4.tgz#a0265ee655476fc807aea9df3df8df7783808b4f" 438 | integrity sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ== 439 | dependencies: 440 | string-width "^4.2.0" 441 | strip-ansi "^6.0.0" 442 | wrap-ansi "^7.0.0" 443 | 444 | color-convert@^2.0.1: 445 | version "2.0.1" 446 | resolved "https://registry.npmmirror.com/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3" 447 | integrity sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ== 448 | dependencies: 449 | color-name "~1.1.4" 450 | 451 | color-name@~1.1.4: 452 | version "1.1.4" 453 | resolved "https://registry.npmmirror.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" 454 | integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== 455 | 456 | csstype@^2.6.8: 457 | version "2.6.21" 458 | resolved "https://registry.npmmirror.com/csstype/-/csstype-2.6.21.tgz#2efb85b7cc55c80017c66a5ad7cbd931fda3a90e" 459 | integrity sha512-Z1PhmomIfypOpoMjRQB70jfvy/wxT50qW08YXO5lMIJkrdq4yOTR+AW7FqutScmB9NkLwxo+jU+kZLbofZZq/w== 460 | 461 | emoji-regex@^8.0.0: 462 | version "8.0.0" 463 | resolved "https://registry.npmmirror.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37" 464 | integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A== 465 | 466 | esbuild@^0.17.5: 467 | version "0.17.15" 468 | resolved "https://registry.npmmirror.com/esbuild/-/esbuild-0.17.15.tgz#209ebc87cb671ffb79574db93494b10ffaf43cbc" 469 | integrity sha512-LBUV2VsUIc/iD9ME75qhT4aJj0r75abCVS0jakhFzOtR7TQsqQA5w0tZ+KTKnwl3kXE0MhskNdHDh/I5aCR1Zw== 470 | optionalDependencies: 471 | "@esbuild/android-arm" "0.17.15" 472 | "@esbuild/android-arm64" "0.17.15" 473 | "@esbuild/android-x64" "0.17.15" 474 | "@esbuild/darwin-arm64" "0.17.15" 475 | "@esbuild/darwin-x64" "0.17.15" 476 | "@esbuild/freebsd-arm64" "0.17.15" 477 | "@esbuild/freebsd-x64" "0.17.15" 478 | "@esbuild/linux-arm" "0.17.15" 479 | "@esbuild/linux-arm64" "0.17.15" 480 | "@esbuild/linux-ia32" "0.17.15" 481 | "@esbuild/linux-loong64" "0.17.15" 482 | "@esbuild/linux-mips64el" "0.17.15" 483 | "@esbuild/linux-ppc64" "0.17.15" 484 | "@esbuild/linux-riscv64" "0.17.15" 485 | "@esbuild/linux-s390x" "0.17.15" 486 | "@esbuild/linux-x64" "0.17.15" 487 | "@esbuild/netbsd-x64" "0.17.15" 488 | "@esbuild/openbsd-x64" "0.17.15" 489 | "@esbuild/sunos-x64" "0.17.15" 490 | "@esbuild/win32-arm64" "0.17.15" 491 | "@esbuild/win32-ia32" "0.17.15" 492 | "@esbuild/win32-x64" "0.17.15" 493 | 494 | escalade@^3.1.1: 495 | version "3.1.1" 496 | resolved "https://registry.npmmirror.com/escalade/-/escalade-3.1.1.tgz#d8cfdc7000965c5a0174b4a82eaa5c0552742e40" 497 | integrity sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw== 498 | 499 | estree-walker@^2.0.2: 500 | version "2.0.2" 501 | resolved "https://registry.npmmirror.com/estree-walker/-/estree-walker-2.0.2.tgz#52f010178c2a4c117a7757cfe942adb7d2da4cac" 502 | integrity sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w== 503 | 504 | fsevents@~2.3.2: 505 | version "2.3.2" 506 | resolved "https://registry.npmmirror.com/fsevents/-/fsevents-2.3.2.tgz#8a526f78b8fdf4623b709e0b975c52c24c02fd1a" 507 | integrity sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA== 508 | 509 | function-bind@^1.1.1: 510 | version "1.1.1" 511 | resolved "https://registry.npmmirror.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d" 512 | integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A== 513 | 514 | get-caller-file@^2.0.5: 515 | version "2.0.5" 516 | resolved "https://registry.npmmirror.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e" 517 | integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg== 518 | 519 | has@^1.0.3: 520 | version "1.0.3" 521 | resolved "https://registry.npmmirror.com/has/-/has-1.0.3.tgz#722d7cbfc1f6aa8241f16dd814e011e1f41e8796" 522 | integrity sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw== 523 | dependencies: 524 | function-bind "^1.1.1" 525 | 526 | is-core-module@^2.11.0: 527 | version "2.11.0" 528 | resolved "https://registry.npmmirror.com/is-core-module/-/is-core-module-2.11.0.tgz#ad4cb3e3863e814523c96f3f58d26cc570ff0144" 529 | integrity sha512-RRjxlvLDkD1YJwDbroBHMb+cukurkDWNyHx7D3oNB5x9rb5ogcksMC5wHCadcXoo67gVr/+3GFySh3134zi6rw== 530 | dependencies: 531 | has "^1.0.3" 532 | 533 | is-fullwidth-code-point@^3.0.0: 534 | version "3.0.0" 535 | resolved "https://registry.npmmirror.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz#f116f8064fe90b3f7844a38997c0b75051269f1d" 536 | integrity sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg== 537 | 538 | jsonc-parser@^3.2.0: 539 | version "3.2.0" 540 | resolved "https://registry.npmmirror.com/jsonc-parser/-/jsonc-parser-3.2.0.tgz#31ff3f4c2b9793f89c67212627c51c6394f88e76" 541 | integrity sha512-gfFQZrcTc8CnKXp6Y4/CBT3fTc0OVuDofpre4aEeEpSBPV5X5v4+Vmx+8snU7RLPrNHPKSgLxGo9YuQzz20o+w== 542 | 543 | magic-string@^0.25.7: 544 | version "0.25.9" 545 | resolved "https://registry.npmmirror.com/magic-string/-/magic-string-0.25.9.tgz#de7f9faf91ef8a1c91d02c2e5314c8277dbcdd1c" 546 | integrity sha512-RmF0AsMzgt25qzqqLc1+MbHmhdx0ojF2Fvs4XnOqz2ZOBXzzkEwc/dJQZCYHAn7v1jbVOjAZfK8msRn4BxO4VQ== 547 | dependencies: 548 | sourcemap-codec "^1.4.8" 549 | 550 | nanoid@^3.3.4: 551 | version "3.3.6" 552 | resolved "https://registry.npmmirror.com/nanoid/-/nanoid-3.3.6.tgz#443380c856d6e9f9824267d960b4236ad583ea4c" 553 | integrity sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA== 554 | 555 | path-parse@^1.0.7: 556 | version "1.0.7" 557 | resolved "https://registry.npmmirror.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735" 558 | integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw== 559 | 560 | picocolors@^1.0.0: 561 | version "1.0.0" 562 | resolved "https://registry.npmmirror.com/picocolors/-/picocolors-1.0.0.tgz#cb5bdc74ff3f51892236eaf79d68bc44564ab81c" 563 | integrity sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ== 564 | 565 | postcss@^8.1.10, postcss@^8.4.21: 566 | version "8.4.21" 567 | resolved "https://registry.npmmirror.com/postcss/-/postcss-8.4.21.tgz#c639b719a57efc3187b13a1d765675485f4134f4" 568 | integrity sha512-tP7u/Sn/dVxK2NnruI4H9BG+x+Wxz6oeZ1cJ8P6G/PZY0IKk4k/63TDsQf2kQq3+qoJeLm2kIBUNlZe3zgb4Zg== 569 | dependencies: 570 | nanoid "^3.3.4" 571 | picocolors "^1.0.0" 572 | source-map-js "^1.0.2" 573 | 574 | preact@^10.0.0: 575 | version "10.13.2" 576 | resolved "https://registry.npmmirror.com/preact/-/preact-10.13.2.tgz#2c40c73d57248b57234c4ae6cd9ab9d8186ebc0a" 577 | integrity sha512-q44QFLhOhty2Bd0Y46fnYW0gD/cbVM9dUVtNTDKPcdXSMA7jfY+Jpd6rk3GB0lcQss0z5s/6CmVP0Z/hV+g6pw== 578 | 579 | require-directory@^2.1.1: 580 | version "2.1.1" 581 | resolved "https://registry.npmmirror.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" 582 | integrity sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q== 583 | 584 | resolve@^1.22.1: 585 | version "1.22.2" 586 | resolved "https://registry.npmmirror.com/resolve/-/resolve-1.22.2.tgz#0ed0943d4e301867955766c9f3e1ae6d01c6845f" 587 | integrity sha512-Sb+mjNHOULsBv818T40qSPeRiuWLyaGMa5ewydRLFimneixmVy2zdivRl+AF6jaYPC8ERxGDmFSiqui6SfPd+g== 588 | dependencies: 589 | is-core-module "^2.11.0" 590 | path-parse "^1.0.7" 591 | supports-preserve-symlinks-flag "^1.0.0" 592 | 593 | rollup@^3.18.0: 594 | version "3.20.2" 595 | resolved "https://registry.npmmirror.com/rollup/-/rollup-3.20.2.tgz#f798c600317f216de2e4ad9f4d9ab30a89b690ff" 596 | integrity sha512-3zwkBQl7Ai7MFYQE0y1MeQ15+9jsi7XxfrqwTb/9EK8D9C9+//EBR4M+CuA1KODRaNbFez/lWxA5vhEGZp4MUg== 597 | optionalDependencies: 598 | fsevents "~2.3.2" 599 | 600 | shiki@^0.14.1: 601 | version "0.14.1" 602 | resolved "https://registry.npmmirror.com/shiki/-/shiki-0.14.1.tgz#9fbe082d0a8aa2ad63df4fbf2ee11ec924aa7ee1" 603 | integrity sha512-+Jz4nBkCBe0mEDqo1eKRcCdjRtrCjozmcbTUjbPTX7OOJfEbTZzlUWlZtGe3Gb5oV1/jnojhG//YZc3rs9zSEw== 604 | dependencies: 605 | ansi-sequence-parser "^1.1.0" 606 | jsonc-parser "^3.2.0" 607 | vscode-oniguruma "^1.7.0" 608 | vscode-textmate "^8.0.0" 609 | 610 | source-map-js@^1.0.2: 611 | version "1.0.2" 612 | resolved "https://registry.npmmirror.com/source-map-js/-/source-map-js-1.0.2.tgz#adbc361d9c62df380125e7f161f71c826f1e490c" 613 | integrity sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw== 614 | 615 | source-map@^0.6.1: 616 | version "0.6.1" 617 | resolved "https://registry.npmmirror.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" 618 | integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== 619 | 620 | sourcemap-codec@^1.4.8: 621 | version "1.4.8" 622 | resolved "https://registry.npmmirror.com/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz#ea804bd94857402e6992d05a38ef1ae35a9ab4c4" 623 | integrity sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA== 624 | 625 | string-width@^4.1.0, string-width@^4.2.0: 626 | version "4.2.3" 627 | resolved "https://registry.npmmirror.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" 628 | integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== 629 | dependencies: 630 | emoji-regex "^8.0.0" 631 | is-fullwidth-code-point "^3.0.0" 632 | strip-ansi "^6.0.1" 633 | 634 | strip-ansi@^6.0.0, strip-ansi@^6.0.1: 635 | version "6.0.1" 636 | resolved "https://registry.npmmirror.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" 637 | integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== 638 | dependencies: 639 | ansi-regex "^5.0.1" 640 | 641 | supports-preserve-symlinks-flag@^1.0.0: 642 | version "1.0.0" 643 | resolved "https://registry.npmmirror.com/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz#6eda4bd344a3c94aea376d4cc31bc77311039e09" 644 | integrity sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w== 645 | 646 | vite@^4.2.1: 647 | version "4.2.1" 648 | resolved "https://registry.npmmirror.com/vite/-/vite-4.2.1.tgz#6c2eb337b0dfd80a9ded5922163b94949d7fc254" 649 | integrity sha512-7MKhqdy0ISo4wnvwtqZkjke6XN4taqQ2TBaTccLIpOKv7Vp2h4Y+NpmWCnGDeSvvn45KxvWgGyb0MkHvY1vgbg== 650 | dependencies: 651 | esbuild "^0.17.5" 652 | postcss "^8.4.21" 653 | resolve "^1.22.1" 654 | rollup "^3.18.0" 655 | optionalDependencies: 656 | fsevents "~2.3.2" 657 | 658 | vitepress@^1.0.0-alpha.65: 659 | version "1.0.0-alpha.65" 660 | resolved "https://registry.npmmirror.com/vitepress/-/vitepress-1.0.0-alpha.65.tgz#785268010d3bd1cabeb18011e68d512c9f1d4e0e" 661 | integrity sha512-iGWC0AQC6WrfRZTJf5+TiGG4o8PLhqIJNyai8NVxZCY9YpmMJhddvQeqqjJdQniF/LQK/hQ5nQZ9HgSZDGRPGQ== 662 | dependencies: 663 | "@docsearch/css" "^3.3.3" 664 | "@docsearch/js" "^3.3.3" 665 | "@vitejs/plugin-vue" "^4.1.0" 666 | "@vue/devtools-api" "^6.5.0" 667 | "@vueuse/core" "^9.13.0" 668 | body-scroll-lock "4.0.0-beta.0" 669 | shiki "^0.14.1" 670 | vite "^4.2.1" 671 | vue "^3.2.47" 672 | 673 | vscode-oniguruma@^1.7.0: 674 | version "1.7.0" 675 | resolved "https://registry.npmmirror.com/vscode-oniguruma/-/vscode-oniguruma-1.7.0.tgz#439bfad8fe71abd7798338d1cd3dc53a8beea94b" 676 | integrity sha512-L9WMGRfrjOhgHSdOYgCt/yRMsXzLDJSL7BPrOZt73gU0iWO4mpqzqQzOz5srxqTvMBaR0XZTSrVWo4j55Rc6cA== 677 | 678 | vscode-textmate@^8.0.0: 679 | version "8.0.0" 680 | resolved "https://registry.npmmirror.com/vscode-textmate/-/vscode-textmate-8.0.0.tgz#2c7a3b1163ef0441097e0b5d6389cd5504b59e5d" 681 | integrity sha512-AFbieoL7a5LMqcnOF04ji+rpXadgOXnZsxQr//r83kLPr7biP7am3g9zbaZIaBGwBRWeSvoMD4mgPdX3e4NWBg== 682 | 683 | vue-demi@*: 684 | version "0.13.11" 685 | resolved "https://registry.npmmirror.com/vue-demi/-/vue-demi-0.13.11.tgz#7d90369bdae8974d87b1973564ad390182410d99" 686 | integrity sha512-IR8HoEEGM65YY3ZJYAjMlKygDQn25D5ajNFNoKh9RSDMQtlzCxtfQjdQgv9jjK+m3377SsJXY8ysq8kLCZL25A== 687 | 688 | vue@^3.2.47: 689 | version "3.2.47" 690 | resolved "https://registry.npmmirror.com/vue/-/vue-3.2.47.tgz#3eb736cbc606fc87038dbba6a154707c8a34cff0" 691 | integrity sha512-60188y/9Dc9WVrAZeUVSDxRQOZ+z+y5nO2ts9jWXSTkMvayiWxCWOWtBQoYjLeccfXkiiPZWAHcV+WTPhkqJHQ== 692 | dependencies: 693 | "@vue/compiler-dom" "3.2.47" 694 | "@vue/compiler-sfc" "3.2.47" 695 | "@vue/runtime-dom" "3.2.47" 696 | "@vue/server-renderer" "3.2.47" 697 | "@vue/shared" "3.2.47" 698 | 699 | wrap-ansi@^7.0.0: 700 | version "7.0.0" 701 | resolved "https://registry.npmmirror.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" 702 | integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== 703 | dependencies: 704 | ansi-styles "^4.0.0" 705 | string-width "^4.1.0" 706 | strip-ansi "^6.0.0" 707 | 708 | y18n@^5.0.5: 709 | version "5.0.8" 710 | resolved "https://registry.npmmirror.com/y18n/-/y18n-5.0.8.tgz#7f4934d0f7ca8c56f95314939ddcd2dd91ce1d55" 711 | integrity sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA== 712 | 713 | yargs-parser@^20.2.2: 714 | version "20.2.9" 715 | resolved "https://registry.npmmirror.com/yargs-parser/-/yargs-parser-20.2.9.tgz#2eb7dc3b0289718fc295f362753845c41a0c94ee" 716 | integrity sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w== 717 | 718 | yargs@^16.1.1: 719 | version "16.2.0" 720 | resolved "https://registry.npmmirror.com/yargs/-/yargs-16.2.0.tgz#1c82bf0f6b6a66eafce7ef30e376f49a12477f66" 721 | integrity sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw== 722 | dependencies: 723 | cliui "^7.0.2" 724 | escalade "^3.1.1" 725 | get-caller-file "^2.0.5" 726 | require-directory "^2.1.1" 727 | string-width "^4.2.0" 728 | y18n "^5.0.5" 729 | yargs-parser "^20.2.2" 730 | --------------------------------------------------------------------------------