Compare commits

..
829 Commits
Author SHA1 Message Date
Mr Chen da4a61b716 Merge pull request #775 from midoks/dev
0.18.1
2025-07-12 20:57:46 +08:00
dami 996c4474ec Update version.py 2025-07-12 20:55:05 +08:00
dami cdc05d8d98 update 2025-07-12 20:44:37 +08:00
dami 52892ef5df Update crontab.js 2025-07-12 20:34:50 +08:00
dami ce0340689b Update crontab.py 2025-07-12 20:34:06 +08:00
dami 58cdb0db95 Update crontab.py 2025-07-12 20:28:40 +08:00
dami c2c49d09e9 Update crontab.py 2025-07-12 20:25:14 +08:00
dami c9a2997cea Update backup.py 2025-07-12 20:23:43 +08:00
dami 94aba71ae4 Update backup.py 2025-07-12 20:17:16 +08:00
dami b80c7bdc23 Update backup.py 2025-07-12 20:12:31 +08:00
dami 279231c08c update 2025-07-12 20:12:17 +08:00
dami ef47b839ad Update crontab.py 2025-07-12 19:54:24 +08:00
dami ffc8ae7d04 update 2025-07-12 17:43:45 +08:00
dami 7d8269832f up 2025-07-12 16:42:10 +08:00
dami 6ba516f66e Update default.sql 2025-07-12 14:26:09 +08:00
dami 53d4fcbd6d update 2025-07-12 14:21:04 +08:00
dami 237ef10545 update 2025-07-12 14:19:01 +08:00
dami 23650aa800 update 2025-07-12 14:13:47 +08:00
dami 9998691524 update 2025-07-12 13:59:05 +08:00
dami bd61a953ad Update public.js 2025-07-12 12:45:59 +08:00
dami f53379829c Update public.js 2025-07-12 01:35:49 +08:00
Mr Chen 04a4faba22 Merge pull request #774 from midoks/dev
编辑细节优化
2025-07-12 01:14:08 +08:00
dami 65d4369306 Update public.js 2025-07-12 01:10:42 +08:00
dami 6ab650d498 Update public.js 2025-07-12 00:20:17 +08:00
Mr Chen 2a06c108ac Merge pull request #773 from midoks/dev
Update public.js
2025-07-12 00:15:29 +08:00
dami 3bd31c55fd Update public.js 2025-07-12 00:14:03 +08:00
Mr Chen ea2fb6d4cd Merge pull request #772 from midoks/dev
编辑文件优化
2025-07-11 23:57:12 +08:00
dami d4dccc8016 Update public.js 2025-07-11 23:52:50 +08:00
dami 3cdc78af1f Update push_ad.py 2025-07-11 15:37:26 +08:00
dami 7784f0c929 Update push_notice_msg.py 2025-07-11 15:34:42 +08:00
dami a399d3d04a Update push_notice_msg.py 2025-07-11 15:33:39 +08:00
dami d261dd8fb4 Update push_notice_msg.py 2025-07-11 15:28:57 +08:00
dami 273f475732 up 2025-07-04 08:40:56 +08:00
Mr Chen 35cce62b9b Merge pull request #769 from midoks/dev
修复mysql8+正确关闭二进制日志
2025-07-02 23:12:34 +08:00
dami 7b5d2820ca up 2025-07-02 23:05:45 +08:00
dami 46374cfb2d update 2025-07-02 23:00:48 +08:00
dami 020bfb2abc Update index.py 2025-07-02 22:58:07 +08:00
dami d3ab317b34 Update index.py 2025-07-02 22:57:15 +08:00
dami da3dd52484 Update index.py 2025-07-02 22:54:38 +08:00
dami 9514cd9cce Update my9.0.cnf 2025-07-02 22:52:34 +08:00
dami 654a66062a Update my9.0.cnf 2025-07-02 22:52:18 +08:00
dami 5ac5b13f9d update 2025-06-30 12:13:21 +08:00
Mr Chen 7f39bf5c6e Merge pull request #767 from midoks/dev
Update crontab.py
2025-06-26 17:30:00 +08:00
dami 0e07a10dcf Update crontab.py 2025-06-26 15:45:03 +08:00
Mr Chen 8cbedd00b8 Merge pull request #766 from midoks/dev
acme.sh 定时每7天强制更新
2025-06-25 23:07:56 +08:00
dami d9d3d3fdb4 Update init_cron.py 2025-06-25 23:06:09 +08:00
dami 364c142f0a Update init_cron.py 2025-06-25 23:04:07 +08:00
dami 92c0177c44 Update init_cron.py 2025-06-25 22:59:42 +08:00
dami 6bdca8c37e Update init_cron.py 2025-06-25 22:58:43 +08:00
dami fcb51e727a Update __init__.py 2025-06-25 22:57:34 +08:00
dami 4523a10898 Update __init__.py 2025-06-25 22:56:39 +08:00
dami 4e155c8039 Update init_cron.py 2025-06-25 22:55:40 +08:00
dami 8b9f861f30 Update init_cron.py 2025-06-25 22:54:45 +08:00
Mr Chen 3595ae6066 Merge pull request #765 from midoks/dev
mysql 9.0 兼容优化
2025-06-25 18:55:27 +08:00
dami 351d4a0ad6 Update index.py 2025-06-25 17:26:17 +08:00
dami c6e6771839 Update index.py 2025-06-25 17:21:18 +08:00
dami fb51e0fcd1 Update index.py 2025-06-25 17:05:09 +08:00
dami 4fbf9c345d update 2025-06-25 17:03:45 +08:00
dami f3557e9acf update 2025-06-25 17:01:24 +08:00
dami cb7367264b Update index.py 2025-06-25 16:53:15 +08:00
dami 2fb722edbf Update index.py 2025-06-25 16:50:22 +08:00
dami fce1608403 Update index.py 2025-06-25 16:46:38 +08:00
dami c6117cb599 update 2025-06-25 16:46:21 +08:00
dami c68e056267 Update index.py 2025-06-25 16:44:55 +08:00
dami 4c9924580a Update index.py 2025-06-25 16:38:37 +08:00
dami 058b3b8d62 Update index.py 2025-06-25 16:36:27 +08:00
dami 1eb29acf7c Update index.py 2025-06-25 16:35:16 +08:00
dami 48ac052de8 Update index.py 2025-06-25 16:35:03 +08:00
dami 4863ff2a19 update 2025-06-25 16:32:59 +08:00
dami 0b0fd8ea67 Update index.py 2025-06-25 16:25:48 +08:00
Mr Chen b8f4ed2767 Merge pull request #759 from midoks/dev
Update file.py
2025-06-16 18:44:21 +08:00
dami 732eba7d7d Update file.py 2025-06-16 18:43:19 +08:00
Mr Chen 8b676f3c1b Merge pull request #758 from midoks/dev
Update file.py
2025-06-12 15:40:50 +08:00
dami 960ca4deca Update file.py 2025-06-12 15:37:14 +08:00
Mr Chen 63ecec4edb Merge pull request #757 from midoks/dev
bug! 根目录解压引起所有目录权限发生变化-限制
2025-06-12 15:18:40 +08:00
dami c6f04aa26f Update file.py 2025-06-12 15:18:22 +08:00
dami 8f29df66d5 Update file.py 2025-06-12 15:11:12 +08:00
dami 2d9e62aedb Update file.py 2025-06-12 15:10:25 +08:00
dami eba511add2 Update file.py 2025-06-12 15:09:42 +08:00
Mr Chen e9e38d5224 Merge pull request #756 from midoks/dev
Update setting.py
2025-06-12 13:18:59 +08:00
dami b131ba8b93 Update setting.py 2025-06-12 13:17:44 +08:00
Mr Chen a12046fe93 Merge pull request #755 from midoks/dev
简单优化
2025-06-12 08:11:46 +08:00
dami 769f065bdf update 2025-06-12 08:10:42 +08:00
dami 81f9ee5eca Update git.tpl 2025-06-09 23:03:14 +08:00
dami 42fb44dd15 Update backup.py 2025-06-09 19:09:50 +08:00
dami 600bb8b516 Update site.py 2025-06-04 15:58:34 +08:00
Mr Chen 8831d91cbe Merge pull request #753 from midoks/dev
PHP GD优化
2025-06-04 15:48:29 +08:00
dami d7d734565c Update gd_old.sh 2025-06-04 15:45:06 +08:00
dami 791e9bf156 Update gd_old.sh 2025-06-04 15:43:20 +08:00
dami 284812b4e3 Update gd_old.sh 2025-06-04 15:43:05 +08:00
dami 505d59bc77 Update install.sh 2025-06-04 12:47:52 +08:00
Mr Chen 02eda25aaf Merge pull request #751 from midoks/dev
优化
2025-05-29 19:11:46 +08:00
dami d19521810e Update __init__.py 2025-05-29 19:10:41 +08:00
dami f8d17724f9 update 2025-05-29 19:07:51 +08:00
Mr Chen 6548125747 Merge pull request #750 from midoks/dev
常规优化
2025-05-29 18:51:51 +08:00
dami ef375619b6 php 默认的 mysql 连接配置,可支持localhost连接 2025-05-29 18:49:17 +08:00
dami fe89ae1846 Update index.py 2025-05-29 18:45:55 +08:00
dami 4ccf142917 Update push_ad.py 2025-05-27 16:38:50 +08:00
Mr Chen 89fbeb85a2 Merge pull request #749 from midoks/dev
debian ufw 规则识别有优化
2025-05-27 11:09:07 +08:00
dami 62b3d15991 Update firewall.py 2025-05-27 11:04:38 +08:00
dami 52a305f5cd Update firewall.py 2025-05-27 11:01:21 +08:00
Mr Chen 658305ef28 Merge pull request #748 from midoks/dev
ACME泛域名SSL申请 第二次优化
2025-05-25 20:38:09 +08:00
dami 19295e2832 Update common.js 2025-05-25 20:37:22 +08:00
dami 719e8165f1 Update common.js 2025-05-25 20:20:10 +08:00
Mr Chen d5ba280654 Merge pull request #747 from midoks/dev
ACME泛域名SSL - 插件优化
2025-05-25 20:14:53 +08:00
dami 00dc48b439 Update index.py 2025-05-25 20:11:06 +08:00
dami 8cc87ba7a0 Update acme.sql 2025-05-25 20:04:59 +08:00
dami 8b2f7ee188 Update common.js 2025-05-25 20:03:18 +08:00
dami 167c551b89 Update common.js 2025-05-25 20:02:42 +08:00
dami b57968d106 Update common.js 2025-05-25 19:57:26 +08:00
dami 68514b8eae Update index.py 2025-05-25 19:27:54 +08:00
dami 88a8e35793 Update tool_cron.py 2025-05-25 19:21:34 +08:00
dami ec4dcb2720 Update tool_cron.py 2025-05-25 19:20:15 +08:00
dami f01b64edd5 Update goedge.py 2025-05-25 19:05:10 +08:00
dami ef0b2af84b Update tool_cron.py 2025-05-25 19:04:55 +08:00
dami 90af2e0c3c Update install.sh 2025-05-25 01:59:46 +08:00
dami 344393244e Update info.json 2025-05-25 01:54:21 +08:00
dami 96c75eb2d3 php优化 2025-05-25 00:14:07 +08:00
dami 5594cbd1a8 php优化 2025-05-25 00:09:40 +08:00
Mr Chen cb87abf19a Merge pull request #746 from midoks/dev
Update __init__.py
2025-05-24 23:06:48 +08:00
dami bf21399113 Update __init__.py 2025-05-24 23:06:24 +08:00
Mr Chen f0fc8a644b Merge pull request #745 from midoks/dev
放开子目录绑定
2025-05-24 19:32:18 +08:00
dami a668234f2a Update site.py 2025-05-24 19:31:35 +08:00
dami 6e80450e37 Update __init__.py 2025-05-24 18:54:20 +08:00
dami 5639be6713 Update monitor.py 2025-05-24 18:48:57 +08:00
dami d36da3dc59 Update init.py 2025-05-24 18:45:59 +08:00
dami e83c743908 Update __init__.py 2025-05-24 18:45:41 +08:00
dami 3410103859 Update default.sql 2025-05-24 18:45:36 +08:00
dami 2685d9ebec Update .gitignore 2025-05-24 18:40:56 +08:00
dami c5574b3d93 Update site.js 2025-05-24 15:41:30 +08:00
dami 832d65bac8 Update default.sql 2025-05-24 15:10:00 +08:00
dami 8394f43b3f Update default.sql 2025-05-24 15:09:46 +08:00
Mr Chen c77ab16f3b Merge pull request #744 from midoks/dev
ssh连接优化
2025-05-24 01:16:31 +08:00
dami 2d10a3a69e Update ssh_local.py 2025-05-24 01:05:41 +08:00
dami 90714961eb Update ssh_local.py 2025-05-24 01:04:26 +08:00
dami b2586adda0 Update ssh_local.py 2025-05-24 01:03:31 +08:00
dami d11dbbccb7 Update ssh_local.py 2025-05-24 01:03:08 +08:00
dami 1390afae0e Update ssh_local.py 2025-05-24 01:00:59 +08:00
dami 3ec2d5e757 Update ssh_terminal.py 2025-05-24 00:56:16 +08:00
dami cc0d0407af Update ssh_terminal.py 2025-05-24 00:56:05 +08:00
dami 1e9e437b1c update 2025-05-24 00:54:02 +08:00
dami eae75e24f9 Update ssh_terminal.py 2025-05-24 00:53:34 +08:00
dami 045d672d68 Update ssh_local.py 2025-05-24 00:51:38 +08:00
dami caeff7de55 Update ssh_local.py 2025-05-24 00:51:29 +08:00
dami b2785070bc Update ssh_terminal.py 2025-05-24 00:46:53 +08:00
dami 545dbeecca 先尝试默认端口 2025-05-24 00:44:49 +08:00
dami b4fa69642c Update index.py 2025-05-23 23:44:08 +08:00
dami f84fcc035c Update git.tpl 2025-05-23 23:43:04 +08:00
dami f556eb9607 Update git.tpl 2025-05-23 23:41:32 +08:00
dami b8aa2ffc38 Update index.py 2025-05-23 23:36:46 +08:00
dami 2be79ead78 Update index.py 2025-05-23 23:36:12 +08:00
dami c900048329 update 2025-05-23 23:35:02 +08:00
dami b7850eaa29 Update index.py 2025-05-23 23:22:27 +08:00
dami ec5a5c8d15 Update index.py 2025-05-23 23:21:20 +08:00
dami 94c51196cf Update requirements.txt 2025-05-23 23:07:23 +08:00
dami 35c18c807f Update requirements.txt 2025-05-23 23:02:48 +08:00
dami da3d44fc2a Update requirements.txt 2025-05-23 23:00:34 +08:00
Mr Chen b9b9ab9006 Merge pull request #743 from midoks/dev
mariadb数据库备份问题
2025-05-23 17:18:16 +08:00
dami 5df23c79e7 Update backup.py 2025-05-23 15:08:00 +08:00
Mr Chen ee4d49752d Merge pull request #741 from midoks/dev
简单优化
2025-05-19 03:18:05 +08:00
dami d26bf25359 Update mw.py 2025-05-19 02:40:33 +08:00
dami b1edc7b2fb Update site.py 2025-05-18 16:14:01 +08:00
dami 459fb086d0 update 2025-05-18 14:12:01 +08:00
Mr Chen 7872391c54 Merge pull request #740 from midoks/dev
webhook优化
2025-05-18 11:09:20 +08:00
dami c2f4171ee9 update 2025-05-18 11:04:56 +08:00
dami 9fdfa1c22f Update git.tpl 2025-05-18 10:23:23 +08:00
dami 8ad3018fe7 Update git.tpl 2025-05-18 10:22:33 +08:00
dami 64883aa424 update 2025-05-18 10:20:03 +08:00
dami 6a41f68289 update 2025-05-18 09:40:10 +08:00
dami ffd96b03e5 Update commit.tpl 2025-05-17 21:17:50 +08:00
dami 961dd5a56e Update index.py 2025-05-17 21:07:59 +08:00
Mr Chen f5cb8ba23d Merge pull request #739 from midoks/dev
简单的优化
2025-05-16 23:57:46 +08:00
dami 6bfe9ea2af Update info.json 2025-05-16 23:48:35 +08:00
dami 134b9ce2f2 php最新版本 2025-05-16 23:44:57 +08:00
dami 54582fb676 mysql配置优化 2025-05-16 23:31:08 +08:00
Mr Chen 2e9864be2a Merge pull request #738 from midoks/dev
面板关联优化
2025-05-16 19:08:50 +08:00
dami 73f01522ed Update public.js 2025-05-16 19:06:48 +08:00
Mr Chen 73a67ebdd6 Merge pull request #736 from midoks/dev
文件管理-右键菜单优化
2025-05-16 04:19:14 +08:00
dami 92c000f63e 右键菜单优化 2025-05-16 04:15:24 +08:00
dami 665d278b52 Update index.py 2025-05-16 02:56:35 +08:00
dami 9393775e90 Update index.py 2025-05-16 02:55:28 +08:00
Mr Chen fe441c7afe Merge pull request #735 from midoks/dev
mysql9的同步优化
2025-05-16 02:51:06 +08:00
dami c865ff433b Update index.py 2025-05-16 02:49:16 +08:00
dami 7eb729e809 Update index.py 2025-05-16 02:41:41 +08:00
Mr Chen f667fbff55 Merge pull request #734 from midoks/dev
细节调优
2025-05-16 02:06:31 +08:00
dami 7c6b5bb200 Update file.py 2025-05-16 02:03:52 +08:00
dami d00ee1a35a Update file.py 2025-05-16 02:02:20 +08:00
Mr Chen 7364e19051 Merge pull request #733 from midoks/dev
优化
2025-05-16 01:56:29 +08:00
dami 97263ba55d Update files.js 2025-05-16 01:55:42 +08:00
dami a9cccbb85f Update files.js 2025-05-16 01:55:35 +08:00
Mr Chen 732bdd5a1c Merge pull request #732 from midoks/dev
支持多种压缩和解压
2025-05-16 01:48:53 +08:00
dami 2934d8fd7d 支持多种压缩和解压
7z,tgz,zip,rar
2025-05-16 01:47:31 +08:00
dami 992555e80e Update cmd.md 2025-05-10 14:51:54 +08:00
dami 4a1348403a Update app.sh 2025-05-06 15:42:15 +08:00
Mr Chen 6353a4dc58 Merge pull request #731 from midoks/dev
redis/memcached版本更新
2025-05-03 10:35:45 +08:00
dami 9e45f493c6 update 2025-05-03 10:34:03 +08:00
dami 66fc8c43db Update info.json 2025-05-03 10:31:26 +08:00
dami e4761d52bc Update info.json 2025-05-03 10:29:30 +08:00
Mr Chen 893eccfa07 Merge pull request #730 from midoks/dev
PHP最新版本
2025-05-01 23:05:58 +08:00
dami fc3dc8276a update 2025-05-01 21:01:05 +08:00
Mr Chen 9ab5e3354d Merge pull request #729 from midoks/dev
基本优化
2025-05-01 15:32:53 +08:00
dami ec607798b5 Update index.py 2025-05-01 15:31:13 +08:00
dami b01a2d15de Update index.py 2025-05-01 15:29:14 +08:00
dami 7e3f40cb20 系统优化加入hosts修改 2025-05-01 15:22:50 +08:00
dami 7a38224198 Update install.sh 2025-05-01 11:56:32 +08:00
dami 5a4f1c3cce update ad 2025-05-01 09:46:23 +08:00
dami f5287e42ca update 2025-05-01 09:45:57 +08:00
Mr Chen 3ec02b8ead Merge pull request #728 from midoks/dev
0.17.0升级0.18.0升级后,站点修复
2025-04-26 18:15:41 +08:00
dami d25e4b3093 0.17.0升级0.18.0升级后,站点修复 2025-04-26 18:14:29 +08:00
dami 0b81a1402e Update site_reflect.py 2025-04-26 17:54:05 +08:00
dami 891ba787e1 Update site_reflect.py 2025-04-26 17:53:40 +08:00
dami 85a85a83e4 Update site_reflect.py 2025-04-26 02:51:09 +08:00
dami 449b4e6882 Update site_reflect.py 2025-04-26 01:43:59 +08:00
dami fba98f5ed6 up 2025-04-26 00:32:43 +08:00
dami fda19b6103 update 2025-04-18 19:51:49 +08:00
Mr Chen d6d2325506 Merge pull request #727 from midoks/dev
OP防火墙修复
2025-04-16 00:54:01 +08:00
dami d4354f1a65 update 2025-04-16 00:49:45 +08:00
dami 7ebe82cf9c Update install.sh 2025-04-16 00:34:08 +08:00
dami 3029f8d263 update 2025-04-15 23:49:42 +08:00
Mr Chen 00d3aaeb22 Merge pull request #726 from midoks/dev
修复mysql问题
2025-04-14 16:59:13 +08:00
dami a8bd5cbbeb Update index.py 2025-04-14 16:57:05 +08:00
dami 48bcf77deb Create mysql9.2.service.tpl 2025-04-14 16:54:00 +08:00
Mr Chen a24f3b72bd Merge pull request #725 from midoks/dev
mysql优化
2025-04-14 16:39:53 +08:00
dami e916e134dc update 2025-04-14 16:22:51 +08:00
dami b9b18b063c Update index.py 2025-04-14 16:00:22 +08:00
dami 753460c594 Update index.py 2025-04-14 15:59:52 +08:00
dami e6f8e3e6e3 Update index.py 2025-04-14 15:49:30 +08:00
dami 952c6da41c Update push_notice_msg.py 2025-04-14 15:27:19 +08:00
dami adb1d0b26d update 2025-04-14 15:24:30 +08:00
Mr Chen 15efadfa9e Merge pull request #723 from midoks/dev
网站统计安装优化
2025-04-13 16:05:48 +08:00
dami f09cc4996b Update install.sh 2025-04-13 16:04:55 +08:00
dami 01a81156cc Create install.old.sh 2025-04-13 15:58:27 +08:00
dami 89ee88d734 Update logs.py 2025-04-12 14:20:28 +08:00
Mr Chen 23880fdb91 Merge pull request #721 from midoks/dev
简单优化
2025-04-12 14:09:38 +08:00
dami 10628d1c69 Update logs.py 2025-04-12 13:56:38 +08:00
dami 897e54cb86 Update pg.py 2025-04-09 11:41:01 +08:00
dami 85da840688 update 2025-04-08 18:21:53 +08:00
dami 10348168eb Update install_dev.sh 2025-04-08 17:58:35 +08:00
dami 4a2570f96a Update install.sh 2025-04-08 17:57:38 +08:00
Mr Chen 65a4635b09 Merge pull request #720 from midoks/dev
Update files.js
2025-04-05 18:29:31 +08:00
dami 3a5264b783 Update files.js 2025-04-03 00:22:46 +08:00
Mr Chen b5866f2a90 Merge pull request #719 from midoks/dev
mysql9.0优化
2025-04-02 16:22:02 +08:00
dami a35913ab78 update 2025-04-02 16:21:16 +08:00
dami cc27602454 Update index.py 2025-04-02 16:18:44 +08:00
dami 8920a1132c Update index.py 2025-04-02 16:07:40 +08:00
dami 536c76b000 Update index.py 2025-04-02 15:42:06 +08:00
dami d054f7f9cd Update index.py 2025-04-02 15:39:59 +08:00
Mr Chen 16bab8f0fa Merge pull request #718 from midoks/dev
mysql9.0相关优化
2025-04-02 13:01:39 +08:00
dami b7aa774eb7 Update index.py 2025-04-02 12:53:11 +08:00
dami cef521390a Update index.py 2025-04-02 12:50:50 +08:00
dami f4cda4ec36 Update index.py 2025-04-02 12:48:38 +08:00
dami 628b65a569 update 2025-04-02 12:48:06 +08:00
dami 142f0fc6c9 Update install.sh 2025-04-02 11:06:47 +08:00
dami fe0f3f63a2 Update index.py 2025-04-01 22:02:42 +08:00
Mr Chen dd3f5fdb0c Merge pull request #716 from midoks/dev
修复bug(crontab)
2025-03-29 14:09:38 +08:00
Mr Chen b7dd2fa05d Merge pull request #715 from moonlightwatch/fix/crontab_echo_name_error
fix: rename cron_name to cron_shell
2025-03-29 14:08:16 +08:00
moonlightwatch 1cf471704c fix: rename cron_name to cron_shell 2025-03-29 14:04:21 +08:00
dami 54f8fdeec2 Update my9.2.cnf 2025-03-26 01:20:21 +08:00
dami 7ea45e4c0a Update my9.2.cnf 2025-03-26 01:17:27 +08:00
dami 5b93e616dc Update my9.2.cnf 2025-03-26 01:13:14 +08:00
dami 2c4176de32 Update index.py 2025-03-26 01:07:25 +08:00
dami 114dcea023 update 2025-03-26 00:57:45 +08:00
dami 3c6b5f3573 update 2025-03-25 12:53:08 +08:00
Mr Chen 258b9b610f Merge pull request #713 from midoks/dev
mysql关闭/开启 二进制日志优化
2025-03-25 12:49:22 +08:00
dami 717d2b1ad0 mariadb更新 2025-03-25 12:48:32 +08:00
dami 3cdd7027d6 Update index.py 2025-03-25 12:45:42 +08:00
dami c5dc755cb6 Update index.py 2025-03-25 12:45:00 +08:00
dami 89d13494c0 Update index.py 2025-03-25 12:43:24 +08:00
dami 6fe6f55df8 Update info.json 2025-03-25 12:26:05 +08:00
dami 2f38ecf505 update 2025-03-25 12:21:18 +08:00
dami c4ba4b4702 Create my9.2.cnf 2025-03-25 12:19:43 +08:00
dami eab13531d4 Update index.py 2025-03-25 12:06:48 +08:00
dami 62d78dbed8 update 2025-03-25 11:55:05 +08:00
dami f5a4f1b275 ad 2025-03-24 23:40:11 +08:00
dami ebe761b1cf Update linux.conf 2025-03-24 11:18:01 +08:00
dami 6e754f2f7b Update __init__.py 2025-03-24 10:38:37 +08:00
dami 39cd3d1f4d Update init_cron.py 2025-03-24 00:06:42 +08:00
dami 778d595e6e Update crontab.py 2025-03-23 18:24:41 +08:00
dami 5f4622fdcd Update init_cron.py 2025-03-23 17:27:43 +08:00
dami 9664609bbd Update init_cron.py 2025-03-23 17:14:49 +08:00
dami aa92699562 Update requirements.txt 2025-03-23 17:14:23 +08:00
dami edc45d5d3b Update mw.tpl 2025-03-23 17:03:31 +08:00
dami ed732232f2 Update mw.tpl 2025-03-23 16:52:14 +08:00
dami db04b3f98a update 2025-03-23 16:50:30 +08:00
dami fb7c5d9d47 update 2025-03-20 11:48:12 +08:00
dami 7d7df74500 Update .gitignore 2025-03-20 00:14:55 +08:00
dami 909ba46f66 Update index.py 2025-03-10 17:55:03 +08:00
dami df84ad25d6 Update info.json 2025-03-10 17:47:42 +08:00
dami 178cfb17f3 Update index.py 2025-03-10 17:43:02 +08:00
dami fcef7ec3ca Update index.py 2025-03-08 14:47:35 +08:00
dami c1e758c9df Revert "Update index.py"
This reverts commit f40cfb7d25.
2025-03-08 14:46:29 +08:00
dami a06c98d52f Revert "Update index.py"
This reverts commit bf49153973.
2025-03-08 14:46:22 +08:00
dami bf49153973 Update index.py 2025-03-08 14:43:55 +08:00
dami f40cfb7d25 Update index.py 2025-03-08 14:37:05 +08:00
Mr Chen dcd4527c75 update 2025-03-06 20:34:57 +08:00
Mr Chen 225ea91f43 Merge pull request #712 from midoks/dev
简单优化
2025-03-01 22:18:31 +08:00
Mr Chen 172ca05efa Update install.sh 2025-03-01 22:17:31 +08:00
Mr Chen b3e2c8d9df Update index.py 2025-02-25 20:22:41 +08:00
Mr Chen 934327052d up 2025-02-23 22:33:02 +08:00
Mr Chen 24a94b4965 Update info.json 2025-02-23 21:59:01 +08:00
Mr Chen c5385541a7 Update tamper_proof_service.py 2025-02-22 10:29:16 +08:00
Mr Chen 5be2d5eb22 Update tamper_proof_service.py 2025-02-22 10:27:23 +08:00
Mr Chen 3688cf6145 Update tamper_proof_service.py 2025-02-22 10:18:45 +08:00
Mr Chen 1328699da0 Merge pull request #710 from jd82k/master
fix bugs
2025-02-21 17:01:13 +08:00
jd82k 1b0e42c79e Update site.py
fix bugs
2025-02-20 22:40:07 -08:00
jd82k 6ca80e3d8c Update site.js
fix bugs
2025-02-20 22:38:37 -08:00
Mr Chen d992541a78 Merge pull request #709 from midoks/dev
openresty1.17.1安装时http3参数缺少
2025-02-19 23:43:24 +08:00
Mr Chen d13adc707e Update install.sh 2025-02-19 23:15:18 +08:00
Mr Chen 90d00d0d9a Update install.sh 2025-02-19 23:11:07 +08:00
Mr Chen fbc9685b3c Merge pull request #708 from midoks/dev
php版本升级
2025-02-18 16:13:34 +08:00
Mr Chen 5507cfdb7b Update install.sh 2025-02-18 16:12:50 +08:00
Mr Chen 2c8de3e7be Create imagemagick.sh 2025-02-16 10:03:47 +08:00
Mr Chen cbba4adb19 Update imagemagick.sh 2025-02-16 09:48:07 +08:00
Mr Chen b1e36d8a71 Update imagemagick.sh 2025-02-16 09:43:42 +08:00
Mr Chen af6403d752 Update imagemagick.sh 2025-02-16 09:42:16 +08:00
Mr Chen 232db27a15 update 2025-02-16 09:15:45 +08:00
Mr Chen e04fc75be0 Update index.py 2025-02-15 22:41:49 +08:00
Mr Chen 5fd4c84a18 Update ubuntu.sh 2025-02-15 22:26:08 +08:00
Mr Chen ce65fb9234 Update imagemagick.sh 2025-02-15 22:21:34 +08:00
Mr Chen d8d8c630a5 update 2025-02-15 22:13:39 +08:00
Mr Chen 08558b1581 Update imagemagick.sh 2025-02-15 21:14:41 +08:00
Mr Chen 21637f170f up 2025-02-14 23:23:58 +08:00
Mr Chen 5013ffd38d Merge pull request #707 from midoks/dev
更新说明
2025-02-13 16:40:20 +08:00
Mr Chen f471368d21 Update README.md 2025-02-13 16:39:51 +08:00
Mr Chen 8ddf0168fd Merge pull request #706 from midoks/dev
webhook插件修复
2025-02-12 12:46:30 +08:00
Mr Chen 5a4ba1297f Update dashboard.py 2025-02-12 12:44:53 +08:00
Mr Chen 0608c531ed Update dashboard.py 2025-02-12 12:41:31 +08:00
Mr Chen 5d242de4e2 update 2025-02-12 12:12:33 +08:00
Mr Chen b7efc0394b update 2025-02-11 01:17:13 +08:00
Mr Chen 16681d0193 Merge pull request #704 from midoks/dev
修复插件安装版本判断
2025-02-10 17:26:53 +08:00
Mr Chen 31ea0865d1 Update plugin.py 2025-02-10 17:23:52 +08:00
Mr Chen 602ad3390c Update README.md 2025-02-06 15:27:41 +08:00
Mr Chen d8891a1767 Merge pull request #702 from midoks/dev
计划任务修复
2025-02-06 00:36:56 +08:00
Mr Chen 2400a0b353 计划任务修复 2025-02-06 00:34:24 +08:00
Mr Chen de0248d59a Merge pull request #701 from midoks/dev
解决ufw识别问题
2025-02-05 19:31:46 +08:00
Mr Chen 3eb72d23f8 Update firewall.py 2025-02-05 19:21:37 +08:00
Mr Chen c0606112b2 update 2025-02-05 19:15:10 +08:00
Mr Chen 5decb77f1e Update ubuntu.sh 2025-02-05 18:49:38 +08:00
Mr Chen a04b9487f1 update 2025-02-03 03:55:05 +08:00
Mr Chen 8835cd4ab5 Update index.py 2025-02-03 03:31:43 +08:00
Mr Chen b17452a949 Update index.py 2025-02-03 03:30:09 +08:00
Mr Chen 2072eee3a4 Update index.py 2025-02-03 03:24:34 +08:00
Mr Chen 4321c0e6b3 up 2025-02-03 03:19:31 +08:00
Mr Chen f1f98b2624 Update index.py 2025-02-03 03:15:26 +08:00
Mr Chen ec37cee26c Update index.py 2025-02-03 03:11:00 +08:00
Mr Chen a8adaf7e5a Update index.py 2025-02-03 03:09:21 +08:00
Mr Chen 84c763c39e Update phplib.conf 2025-02-03 03:06:43 +08:00
Mr Chen 33e86c4f79 Update phplib.conf 2025-02-03 03:03:51 +08:00
Mr Chen c00f93a1d3 Update phplib.conf 2025-02-03 03:03:43 +08:00
Mr Chen 81100f21b4 Update index.py 2025-02-03 02:48:30 +08:00
Mr Chen b8a720919f Update index.py 2025-02-03 02:41:32 +08:00
Mr Chen cba37ae2fc Update lam.js 2025-02-03 02:34:52 +08:00
Mr Chen 5d15cbd4ea Update index.py 2025-02-03 02:29:45 +08:00
Mr Chen 5f87606cf7 Create config.php 2025-02-03 02:29:21 +08:00
Mr Chen 9b22efe3d4 Update index.py 2025-02-03 02:28:13 +08:00
Mr Chen 675c3b27aa Update info.json 2025-02-03 02:26:40 +08:00
Mr Chen ddd9e70d05 Update install.sh 2025-02-03 02:24:24 +08:00
Mr Chen 30ed2049e4 Update info.json 2025-02-03 02:21:19 +08:00
Mr Chen b8092ed6dd Update info.json 2025-02-03 02:19:38 +08:00
Mr Chen c80c0962dd Update info.json 2025-02-03 02:14:16 +08:00
Mr Chen 63c223b237 Update install.sh 2025-02-03 02:13:02 +08:00
Mr Chen 07aa49accc Update install.sh 2025-02-03 02:12:51 +08:00
Mr Chen c595c541fb lam 2025-02-03 02:09:45 +08:00
Mr Chen e6ec8b65ce Update index.py 2025-02-03 01:41:52 +08:00
Mr Chen bc8c455094 Update index.py 2025-02-03 01:39:51 +08:00
Mr Chen 507820d25e Update index.py 2025-02-03 01:31:31 +08:00
Mr Chen 35e08295ce Update install.sh 2025-02-03 01:28:16 +08:00
Mr Chen 9e581d8608 update 2025-02-03 01:25:59 +08:00
Mr Chen dcb8e69aac Create install_debian.sh 2025-01-29 01:15:38 +08:00
Mr Chen 617b354d03 update 2025-01-28 23:41:26 +08:00
Mr Chen 76b095b344 Update config.php 2025-01-28 23:25:36 +08:00
Mr Chen 5ff05e8025 Merge pull request #700 from midoks/dev
网站防串改优化
2025-01-28 22:18:07 +08:00
Mr Chen b973a16247 Update tamper_proof_service.py 2025-01-28 22:06:29 +08:00
Mr Chen 0cb5d7507f Update tamper_proof_py.service.tpl 2025-01-28 22:03:11 +08:00
Mr Chen 2851ebf126 Update tamper_proof_service.py 2025-01-28 22:01:28 +08:00
Mr Chen 2f5b1bb205 update 2025-01-28 22:01:05 +08:00
Mr Chen 5528336698 Update tamper_proof_service.py 2025-01-28 21:52:13 +08:00
Mr Chen 4eda80baa8 Update tamper_proof_service.py 2025-01-28 21:47:48 +08:00
Mr Chen 02918d4bcd Update install.sh 2025-01-28 21:39:22 +08:00
Mr Chen 8315e3ea96 Update phplib.conf 2025-01-28 17:12:43 +08:00
Mr Chen cae4a2ee13 update 2025-01-28 17:09:49 +08:00
Mr Chen 26762eee73 Update phpldapadmin.js 2025-01-28 17:09:03 +08:00
Mr Chen 2f05fb12a0 Update ico.png 2025-01-28 17:06:15 +08:00
Mr Chen befdf2e1d3 Update info.json 2025-01-28 16:58:42 +08:00
Mr Chen aac7b98913 Update phplib.conf 2025-01-28 16:55:15 +08:00
Mr Chen baa9b5e6bb Update phplib.conf 2025-01-28 16:52:09 +08:00
Mr Chen 99c919811a Update phplib.conf 2025-01-28 16:51:03 +08:00
Mr Chen ac7a4e739e Create ldap.sh 2025-01-28 16:49:26 +08:00
Mr Chen f8936aa7bc Update install.sh 2025-01-28 16:44:36 +08:00
Mr Chen 6933c44571 Update index.py 2025-01-28 16:40:20 +08:00
Mr Chen dfb2f4b3af Update index.py 2025-01-28 16:38:19 +08:00
Mr Chen 6601aebddf Update index.py 2025-01-28 16:36:04 +08:00
Mr Chen 4d2ca9587d update 2025-01-28 16:35:10 +08:00
Mr Chen 694a5ceab2 Update index.py 2025-01-28 16:25:53 +08:00
Mr Chen e522093f6c update 2025-01-28 16:25:04 +08:00
Mr Chen feefa2e90a Update install.sh 2025-01-28 16:19:13 +08:00
Mr Chen 3709569cd8 Update install.sh 2025-01-28 16:18:51 +08:00
Mr Chen 052b4870bf Update install.sh 2025-01-28 16:17:35 +08:00
Mr Chen 5cb413a911 Update install.sh 2025-01-28 16:13:36 +08:00
Mr Chen 80e77dda3f update 2025-01-28 16:12:32 +08:00
Mr Chen 7a3d554d6c Update index.py 2025-01-28 16:09:59 +08:00
Mr Chen ab0fb063cf update 2025-01-28 16:08:01 +08:00
Mr Chen caec558bea Update install.sh 2025-01-28 15:52:04 +08:00
Mr Chen 2d44b62fef Update install.sh 2025-01-28 15:50:54 +08:00
Mr Chen f9cc72ba4a update 2025-01-28 15:48:26 +08:00
Mr Chen f8544d0600 update 2025-01-28 15:47:37 +08:00
Mr Chen c96d361b4d Update install.sh 2025-01-28 15:43:27 +08:00
Mr Chen fa5305f332 up 2025-01-28 15:42:56 +08:00
Mr Chen b996bdea93 update 2025-01-28 15:37:08 +08:00
Mr Chen 1bae6538f7 Update index.html 2025-01-28 15:36:30 +08:00
Mr Chen 5673964de4 Update index.py 2025-01-28 15:33:41 +08:00
Mr Chen 25623170bb update 2025-01-28 15:33:14 +08:00
Mr Chen 2aa5739cd8 update 2025-01-28 15:31:34 +08:00
Mr Chen bdff56843f Update index.py 2025-01-28 15:23:45 +08:00
Mr Chen 6e563e6d74 Update index.py 2025-01-28 15:23:30 +08:00
Mr Chen 334a3fb6fe update 2025-01-28 15:20:20 +08:00
Mr Chen a1d130a674 up 2025-01-28 15:02:06 +08:00
Mr Chen e14f2ea247 Update index.py 2025-01-28 14:59:57 +08:00
Mr Chen 3f478eef8e Update install.sh 2025-01-28 14:55:42 +08:00
Mr Chen e929274b51 up 2025-01-28 14:47:07 +08:00
Mr Chen 526c0301f6 Update tamper_proof_service.py 2025-01-28 12:54:53 +08:00
Mr Chen 7e7a19829d Update ubuntu.sh 2025-01-24 17:05:44 +08:00
Mr Chen bc3854b4c4 Update debian.sh 2025-01-24 17:05:31 +08:00
Mr Chen 193bf20a3e Update nginx.conf 2025-01-24 16:01:40 +08:00
Mr Chen 4cc5194939 Merge pull request #698 from midoks/dev
openresty配置优化
2025-01-24 15:49:23 +08:00
Mr Chen 46a525ae09 Update index.py 2025-01-24 15:42:51 +08:00
Mr Chen 6d006a357e Update nginx.conf 2025-01-24 14:28:10 +08:00
Mr Chen fad73b0922 Update push_notice_msg.py 2025-01-17 23:06:40 +08:00
Mr Chen d2d2d4658e update 2025-01-14 18:39:36 +08:00
Mr Chen 84e6ce2b48 ad 2025-01-14 18:37:58 +08:00
Mr Chen b91a9963e2 update 2025-01-14 15:49:03 +08:00
Mr Chen 25fcf93185 Merge pull request #697 from midoks/dev
PHP国内安装优化
2025-01-13 00:07:12 +08:00
Mr Chen 26bb2005c1 Merge pull request #696 from jyeric/patch-1
Fix: Unable to move
2025-01-12 23:58:01 +08:00
jyeric ee58805ae9 Fix: Unable to move 2025-01-12 03:49:32 +08:00
Mr Chen 1bfc02a892 Update install.sh 2025-01-10 23:15:01 +08:00
Mr Chen 0c7dc4dbee up 2025-01-10 23:14:18 +08:00
Mr Chen 42e9859ccb Update install.sh 2025-01-10 23:13:23 +08:00
Mr Chen bf9b6b6046 up 2025-01-10 23:12:56 +08:00
Mr Chen c10eac5190 Merge pull request #694 from midoks/dev
rsyncd优化
2025-01-10 12:13:07 +08:00
Mr Chen d01ccf1208 Update rsyncd.js 2025-01-10 12:10:06 +08:00
Mr Chen 703b9be83e Update rsyncd.js 2025-01-10 12:07:03 +08:00
Mr Chen e0fea93983 update 2025-01-10 12:04:30 +08:00
Mr Chen 84ceef47cb Update index.py 2025-01-10 11:48:20 +08:00
Mr Chen 255ed5944f Update file.py 2025-01-10 11:36:54 +08:00
Mr Chen 0dc2b635ae Merge pull request #693 from midoks/dev
rsyncd同步-接收优化2
2025-01-08 19:46:41 +08:00
Mr Chen ebd1cfe203 Update index.py 2025-01-08 19:45:32 +08:00
Mr Chen 43b9297476 Merge pull request #692 from midoks/dev
冲突解决
2025-01-08 15:18:39 +08:00
Mr Chen aa2f4a0167 Merge branch 'master' into dev 2025-01-08 15:17:30 +08:00
Mr Chen ad31d046d4 Merge pull request #691 from midoks/dev
rsyncd同步-接收优化
2025-01-08 15:10:57 +08:00
Mr Chen a67ad5a7db Update rsyncd.js 2025-01-08 15:07:49 +08:00
Mr Chen 90d4fb245a Update rsyncd.js 2025-01-08 15:06:16 +08:00
Mr Chen 19f55fde6e Update rsyncd.js 2025-01-08 15:03:16 +08:00
Mr Chen 227be5258e up 2025-01-08 15:01:48 +08:00
Mr Chen 913190bfeb Merge pull request #690 from midoks/dev
细节优化
2025-01-08 13:05:46 +08:00
Mr Chen 0b0097f367 Update mw.py 2025-01-08 13:03:13 +08:00
Mr Chen 97ac8264f2 Merge pull request #689 from midoks/dev
Update monitor.html
2025-01-08 00:31:54 +08:00
Mr Chen d9cca6ccc9 Update monitor.html 2025-01-07 23:53:38 +08:00
Mr Chen 28d0b1fd25 Merge pull request #688 from midoks/dev
修复-错误账户登录不能反应的问题2
2025-01-07 18:52:22 +08:00
Mr Chen cbcfe4cb9d Update login.py 2025-01-07 18:51:03 +08:00
Mr Chen 70c14d3369 Merge pull request #687 from midoks/dev
修复-错误账户登录不能反应的问题
2025-01-07 18:44:22 +08:00
Mr Chen 0bcf7edab5 Update login.py 2025-01-07 18:43:39 +08:00
Mr Chen 0f410c29f7 Update login.py 2025-01-07 18:37:57 +08:00
Mr Chen b451a6da25 错误登录判断 2025-01-07 18:37:24 +08:00
Mr Chen e6c7bc1544 Merge pull request #686 from midoks/dev
php openssl编译优化
2025-01-07 17:10:58 +08:00
Mr Chen d1ff8f1cac update 2025-01-07 17:06:45 +08:00
Mr Chen d967100c14 update 2025-01-07 16:25:52 +08:00
Mr Chen 8461c20e40 update 2025-01-07 16:24:39 +08:00
Mr Chen 52924f06d2 Merge pull request #684 from midoks/dev
增加命令-修改面板ip
2025-01-07 01:38:47 +08:00
Mr Chen fad4e7bd7d update 2025-01-07 01:36:17 +08:00
Mr Chen 666ee1a083 Merge pull request #683 from midoks/dev
修复计划任务-每星期修改
2025-01-06 22:00:20 +08:00
Mr Chen 8f05e47363 修复计划任务-每星期修改 2025-01-06 21:58:31 +08:00
Mr Chen 67d8abf7bf Merge pull request #682 from midoks/dev
反向代理优化
2025-01-06 11:39:43 +08:00
Mr Chen 30842a6659 Update site.py 2025-01-06 11:34:56 +08:00
Mr Chen 3ee500d339 Update alist.tpl 2025-01-05 21:57:31 +08:00
Mr Chen c5ade905b0 Merge pull request #681 from midoks/dev
php mysql_xdevapi 在debian下载安装优化
2025-01-04 16:13:45 +08:00
Mr Chen 8e6784bf21 update 2025-01-04 16:10:44 +08:00
Mr Chen 4eacbca674 update 2025-01-04 16:09:04 +08:00
Mr Chen 149fe72324 Merge pull request #680 from midoks/dev
关于phpmyadmin无法连接高级版本的问题【已解决】
2025-01-04 13:18:37 +08:00
Mr Chen 43f752afbc update 2025-01-04 13:01:57 +08:00
Mr Chen 19efde1fda update 2025-01-04 13:00:43 +08:00
Mr Chen 98f267057b Update app_start.php 2025-01-04 12:59:22 +08:00
Mr Chen 4f98894ce4 Update app_start.php 2025-01-04 12:56:24 +08:00
Mr Chen 8cb225779e Update app_start.php 2025-01-04 12:55:45 +08:00
Mr Chen 57ff303c39 Update phplib.conf 2025-01-04 12:50:55 +08:00
Mr Chen 29cae6ae6c Update phplib.conf 2025-01-04 12:50:45 +08:00
Mr Chen e0c761bdf0 Update index.py 2025-01-04 12:46:07 +08:00
Mr Chen 6ee1a8dc52 Update mw.py 2025-01-04 12:41:57 +08:00
Mr Chen db69532dde Update openssl.sh 2025-01-04 12:12:23 +08:00
Mr Chen d4c47c16e4 Update all_test.sh 2025-01-04 11:56:03 +08:00
Mr Chen a28733521b update 2025-01-04 11:54:00 +08:00
Mr Chen b957595944 update 2025-01-04 11:53:20 +08:00
Mr Chen b985d42336 update 2025-01-04 11:48:08 +08:00
Mr Chen 9d467a13bb Update index_php.py 2025-01-04 05:33:40 +08:00
Mr Chen 4629d39980 Update index_php.py 2025-01-04 05:23:14 +08:00
Mr Chen 11d245dadf Update index_php.py 2025-01-04 05:22:19 +08:00
Mr Chen bb72b53f19 Update openssl.sh 2025-01-04 04:57:54 +08:00
Mr Chen 3bef89d625 update 2025-01-04 04:39:37 +08:00
Mr Chen 792b1348c1 Update openssl.sh 2025-01-04 04:06:12 +08:00
Mr Chen 7399cd7d45 Update install.sh 2025-01-04 03:39:54 +08:00
Mr Chen d6347f6d4a update 2025-01-04 03:24:04 +08:00
Mr Chen 3b5585193f update 2025-01-04 03:22:56 +08:00
Mr Chen 5efa218247 Update install.sh 2025-01-04 03:20:18 +08:00
Mr Chen e5d312dbf9 Update install.sh 2025-01-04 03:19:49 +08:00
Mr Chen 38e1c07e0b Update install.sh 2025-01-04 02:50:14 +08:00
Mr Chen 809c9ea237 update 2025-01-04 02:37:28 +08:00
Mr Chen 08a41f039b Update install.sh 2025-01-04 02:27:18 +08:00
Mr Chen 3dd14307d0 Update install.sh 2025-01-04 02:25:30 +08:00
Mr Chen 4122c11372 Update my8.0.cnf 2025-01-04 02:02:24 +08:00
Mr Chen 9360a9cd68 Update my8.0.cnf 2025-01-04 01:48:01 +08:00
Mr Chen 24746dab08 update 2025-01-04 01:37:10 +08:00
Mr Chen 8879cba15d Update install.sh 2025-01-04 01:17:39 +08:00
Mr Chen 1b38c60f57 Merge pull request #679 from midoks/dev
时区接口与phpmyadmin/mysql[Tar]优化
2025-01-04 00:35:56 +08:00
Mr Chen 7c944b27dd update 2025-01-04 00:26:31 +08:00
Mr Chen 523e54eeb2 Update index.py 2025-01-03 23:54:04 +08:00
Mr Chen 7b08a3f1bc Update mysql-community.js 2025-01-03 23:49:22 +08:00
Mr Chen 018826e1a3 Update phpmyadmin.js 2025-01-03 23:47:02 +08:00
Mr Chen a36b0b78b3 Merge pull request #678 from midoks/dev
修复phpmysqladmin插件
2025-01-03 22:42:44 +08:00
Mr Chen 19964d39c1 Update phpmyadmin.js 2025-01-03 22:35:36 +08:00
Mr Chen 31fd04456b update 2025-01-03 22:21:02 +08:00
Mr Chen 76cf2e8fa5 update 2025-01-03 22:15:01 +08:00
Mr Chen f6b61c935e Update index.py 2025-01-03 22:12:47 +08:00
Mr Chen c736a04b4f Update debian.sh 2024-12-31 00:34:08 +08:00
Mr Chen 14432fd6f9 Update install.sh 2024-12-27 17:40:13 +08:00
Mr Chen 047d84acb5 Merge pull request #676 from midoks/dev
面板修改用户名修复
2024-12-26 19:55:51 +08:00
Mr Chen 8de4e6a0ee Update user.py 2024-12-26 19:54:37 +08:00
Mr Chen 90fbb0e9ac Update requirements.txt 2024-12-26 19:07:19 +08:00
Mr Chen 041f36ba00 Update requirements.txt 2024-12-26 19:04:48 +08:00
Mr Chen 9e6cc873cb Update update.sh 2024-12-26 18:06:46 +08:00
Mr Chen 20a6ced7b5 Update update.sh 2024-12-26 18:04:28 +08:00
Mr Chen 34d9682cc1 Update update.sh 2024-12-26 18:02:38 +08:00
Mr Chen 4ac797406a Update update.sh 2024-12-26 18:00:42 +08:00
Mr Chen bb3cdb5d85 Update update.sh 2024-12-26 17:56:43 +08:00
Mr Chen 245923d825 Merge pull request #675 from midoks/dev
兼容问题
2024-12-25 21:25:07 +08:00
Mr Chen 41c048594e Update files.js 2024-12-25 21:21:54 +08:00
Mr Chen 1360d2d066 Update files.js 2024-12-25 21:19:53 +08:00
Mr Chen 6286f03432 Merge pull request #674 from midoks/dev
网站目录 选择优化
2024-12-25 16:50:45 +08:00
Mr Chen c7a99cc61b Update files.py 2024-12-25 16:49:31 +08:00
Mr Chen e4aae5147c Update files.py 2024-12-25 16:35:35 +08:00
Mr Chen 2a2e37ca97 Update public.js 2024-12-25 16:32:40 +08:00
Mr Chen a1489959d1 Update site.py 2024-12-25 16:02:41 +08:00
Mr Chen 4561e37167 Update site.py 2024-12-25 15:58:52 +08:00
Mr Chen 9fa04c9a90 Update site.py 2024-12-25 15:58:07 +08:00
Mr Chen aa4951b7fc Update site.py 2024-12-25 15:53:46 +08:00
Mr Chen 53d08c261c Update site.py 2024-12-25 15:53:30 +08:00
Mr Chen 74058243c6 Update site.py 2024-12-25 15:40:24 +08:00
Mr Chen 62223d53be Update php.py 2024-12-25 15:29:35 +08:00
Mr Chen 06d33758eb Merge pull request #673 from midoks/dev
低版本兼容
2024-12-25 15:04:10 +08:00
Mr Chen af85245b06 Update site.js 2024-12-25 14:56:40 +08:00
Mr Chen 01d8ebbd40 update 2024-12-25 14:52:57 +08:00
Mr Chen 1c1cd1f434 Update site.js 2024-12-25 14:51:18 +08:00
Mr Chen aaa801964c Merge pull request #672 from midoks/dev
创建站点兼容问题
2024-12-25 13:00:32 +08:00
Mr Chen 01b490dff1 update 2024-12-25 12:52:41 +08:00
Mr Chen 1be1441352 Merge pull request #671 from midoks/dev
防火墙ssh修改端口修复
2024-12-24 23:08:09 +08:00
Mr Chen 0b47b56fb5 Update firewall.py 2024-12-24 23:05:46 +08:00
Mr Chen 0a1251ad0b Update firewall.py 2024-12-24 23:05:27 +08:00
Mr Chen a506bebc94 Merge pull request #670 from midoks/dev
防火墙添加优化
2024-12-24 22:31:27 +08:00
Mr Chen 26147acfa0 Update firewall.html 2024-12-24 22:27:10 +08:00
Mr Chen f1d0be9f61 Merge pull request #669 from midoks/dev
兼容问题
2024-12-24 19:54:58 +08:00
Mr Chen 45c1e9d28c Update r3.7.txt 2024-12-24 19:52:23 +08:00
Mr Chen df3db9e632 Merge pull request #667 from midoks/dev
修复反向代理设置问题
2024-12-24 02:45:39 +08:00
Mr Chen 8c1e672da7 Update site.py 2024-12-24 02:44:41 +08:00
Mr Chen 4bf5e68a9d Merge pull request #666 from midoks/dev
php版本更新及备份优化
2024-12-24 02:16:49 +08:00
Mr Chen 0d4b157b1b Update backup.py 2024-12-24 02:14:20 +08:00
Mr Chen 5fd207c84c Update backup.py 2024-12-24 02:14:01 +08:00
Mr Chen 6829baba67 Update install.sh 2024-12-23 21:43:22 +08:00
Mr Chen b9983929fc update 2024-12-23 21:42:52 +08:00
Mr Chen d540e7497b Merge pull request #664 from midoks/dev
站点页面和计划页面登录检查
2024-12-22 18:51:31 +08:00
Mr Chen 0e0cc248fa 站点页面和计划页面登录检查 2024-12-22 18:50:58 +08:00
Mr Chen bcf6808e49 Update site.py 2024-12-22 01:33:19 +08:00
Mr Chen e2e27765ee Update site.py 2024-12-22 01:33:08 +08:00
Mr Chen f3b07bda65 Update site.py 2024-12-22 01:03:56 +08:00
Mr Chen f555f1084f Merge pull request #663 from midoks/dev
@ramondelee 专用功能
2024-12-22 00:37:20 +08:00
Mr Chen 212be88efe Update site.js 2024-12-22 00:36:29 +08:00
Mr Chen c131f0ecda Update site.js 2024-12-21 23:12:03 +08:00
Mr Chen e3afb4b481 Merge pull request #662 from midoks/dev
acme手动验证
2024-12-21 20:32:05 +08:00
Mr Chen ca61f70d37 gorse便捷功能 2024-12-21 20:27:51 +08:00
Mr Chen 90850ebfa3 Update site.js 2024-12-21 18:59:46 +08:00
Mr Chen 771a6d6e08 Update site.js 2024-12-21 18:59:06 +08:00
Mr Chen 55a6d17bc8 Update site.py 2024-12-21 18:35:01 +08:00
Mr Chen 649990f2e1 update 2024-12-21 18:19:58 +08:00
Mr Chen 48468a1c2d 右键解压方法缺失 2024-12-21 17:06:08 +08:00
Mr Chen dd685b664d acme手动申请ssl 2024-12-21 15:10:39 +08:00
Mr Chen 36898e3e11 update 2024-12-21 14:19:53 +08:00
Mr Chen 737450ba6e Update ssl_acme.py 2024-12-21 14:15:35 +08:00
Mr Chen 0f63145319 Update rhel.sh 2024-12-21 00:50:29 +08:00
Mr Chen 6a942db113 Update ubuntu.sh 2024-12-21 00:41:42 +08:00
Mr Chen 6119adbe2d Update debian.sh 2024-12-21 00:41:39 +08:00
Mr Chen c31af5cbf4 Update mw.tpl 2024-12-21 00:21:52 +08:00
Mr Chen 784629f11b Update cli.sh 2024-12-21 00:17:28 +08:00
Mr Chen a581b7cdef Merge pull request #659 from midoks/dev
文件大小功能优化
2024-12-20 00:02:37 +08:00
Mr Chen d6918621fa Update files.py 2024-12-19 23:55:16 +08:00
Mr Chen dc54ec241e update 2024-12-19 23:49:57 +08:00
Mr Chen 2f94674479 Update index.py 2024-12-19 23:28:22 +08:00
Mr Chen 10b94514a7 update 2024-12-19 23:10:55 +08:00
Mr Chen f5eacd6016 Merge pull request #658 from midoks/dev
插件优化
2024-12-19 17:28:03 +08:00
Mr Chen 7383317f0b Merge branch 'master' into dev 2024-12-19 17:27:20 +08:00
Mr Chen 26fa9378f5 Update README.md 2024-12-19 17:26:57 +08:00
Mr Chen 9f37033e5c Update plugin.py 2024-12-19 17:24:34 +08:00
Mr Chen dc4ff9b694 Update info.json 2024-12-19 17:12:49 +08:00
Mr Chen 3c9dc0a127 Update info.json 2024-12-19 17:09:48 +08:00
Mr Chen 2afbe1c6fd Merge branch 'master' into dev 2024-12-19 16:38:36 +08:00
Mr Chen 309b5b9563 Merge pull request #657 from midoks/dev
插件位置调整
2024-12-19 16:38:22 +08:00
Mr Chen f64f0ebf4e Update info.json 2024-12-19 16:36:55 +08:00
Mr Chen dd646a155b Update info.json 2024-12-19 16:36:09 +08:00
Mr Chen 6db38826d8 update 2024-12-19 16:34:14 +08:00
Mr Chen a18fd9b05c Update info.json 2024-12-19 16:32:27 +08:00
Mr Chen 611c7b7b21 update 2024-12-19 16:32:06 +08:00
Mr Chen 3961e95a5f update 2024-12-19 16:29:44 +08:00
Mr Chen d6e6a53301 update 2024-12-19 16:26:32 +08:00
Mr Chen e500026017 Update info.json 2024-12-19 16:25:03 +08:00
Mr Chen 84632b6296 Update info.json 2024-12-19 16:24:44 +08:00
Mr Chen 9b79e93967 Update info.json 2024-12-19 16:22:27 +08:00
Mr Chen 88e7ad0411 Merge pull request #656 from midoks/dev
mysql 快速安装 针对ubuntu24进行优化
2024-12-19 16:15:24 +08:00
Mr Chen d0e96eab91 Update install.sh 2024-12-19 16:13:13 +08:00
Mr Chen 6ac78d9eb6 Update install.sh 2024-12-19 16:06:51 +08:00
Mr Chen 5d830ae2f8 Update install.sh 2024-12-19 16:01:52 +08:00
Mr Chen 178f844420 Update install.sh 2024-12-19 16:01:32 +08:00
Mr Chen adf3df510e Update install.sh 2024-12-19 16:01:12 +08:00
Mr Chen f58c03c429 Update install.sh 2024-12-19 16:00:05 +08:00
Mr Chen 15f9edc5c7 Update install.sh 2024-12-19 15:59:22 +08:00
Mr Chen 07f77024ab update 2024-12-19 15:57:26 +08:00
Mr Chen 5b8ff7e612 Update ubuntu.sh 2024-12-19 15:30:57 +08:00
Mr Chen 1182e7405e Merge pull request #655 from midoks/dev
mw命令添加
2024-12-19 15:25:34 +08:00
Mr Chen 9c6d8ef8e6 Update mw.tpl 2024-12-19 15:24:05 +08:00
Mr Chen eb807fb205 Update mw.tpl 2024-12-19 15:22:37 +08:00
Mr Chen 0602fb5569 Merge pull request #654 from midoks/dev
代理优化2
2024-12-19 15:14:41 +08:00
Mr Chen 1dd78c3ea1 Update site.py 2024-12-19 15:11:56 +08:00
Mr Chen 3175de4576 Update version.py 2024-12-19 15:11:00 +08:00
Mr Chen dfd1f172bb Update site.py 2024-12-19 15:09:42 +08:00
Mr Chen 0f6cf01fd3 Merge pull request #653 from midoks/dev
代理配置优化
2024-12-19 15:05:36 +08:00
Mr Chen 3e9e7922b4 Update site.py 2024-12-19 15:01:19 +08:00
Mr Chen eb480c8838 update 2024-12-19 14:43:59 +08:00
Mr Chen a9bc4fe914 Update site.py 2024-12-19 14:21:39 +08:00
Mr Chen 3bf1573e36 Update site.py 2024-12-19 14:20:39 +08:00
Mr Chen de6fd60f41 Update site.py 2024-12-19 14:19:17 +08:00
Mr Chen cf72ebdfd8 Update site.py 2024-12-19 14:17:22 +08:00
Mr Chen 6e44452807 Update site.py 2024-12-19 14:17:12 +08:00
Mr Chen 88c6abb53c Update site.py 2024-12-19 14:14:13 +08:00
Mr Chen 27fd93f590 Update site.py 2024-12-19 14:09:25 +08:00
Mr Chen 8b391f03c2 Update site.py 2024-12-19 14:08:59 +08:00
Mr Chen ea3033e22a Update site.py 2024-12-19 14:07:29 +08:00
Mr Chen c88dff350e Merge pull request #652 from midoks/dev
站点代理+跨域设置
2024-12-18 19:36:08 +03:00
Mr Chen 73e1a312b5 Update version.py 2024-12-19 00:31:08 +08:00
Mr Chen 28c2b6dc77 Update site.py 2024-12-19 00:29:49 +08:00
Mr Chen 0348cc55c6 update 2024-12-19 00:13:22 +08:00
Mr Chen e439918e05 Update site.js 2024-12-18 23:18:25 +08:00
Mr Chen a5a7f405b3 Merge pull request #651 from midoks/dev
代理/重定向功能修复
2024-12-18 18:03:34 +03:00
Mr Chen 4cd620fe2b update 2024-12-18 23:01:38 +08:00
Mr Chen b1826a60d2 Update proxy.py 2024-12-18 22:54:46 +08:00
Mr Chen 50ec1c59d2 设置手动代理配置 2024-12-18 22:53:02 +08:00
Mr Chen 36d604ec49 Update site.py 2024-12-18 22:47:21 +08:00
Mr Chen 7d6407afcf Merge pull request #650 from midoks/dev
Update README.md
2024-12-18 17:43:34 +08:00
Mr Chen 92358db548 Update README.md 2024-12-18 17:34:37 +08:00
Mr Chen 161c6a69b1 Merge pull request #649 from midoks/dev
gdrive优化
2024-12-18 16:15:07 +08:00
Mr Chen 215e053b6d update 2024-12-18 16:10:08 +08:00
Mr Chen e8a99af37f Update install.sh 2024-12-18 15:50:07 +08:00
Mr Chen de258a2568 Update install.sh 2024-12-18 15:49:40 +08:00
Mr Chen 728db39ab7 update 2024-12-18 14:54:35 +08:00
Mr Chen d885870302 Merge pull request #648 from midoks/dev
监控开启设置修复
2024-12-18 14:35:25 +08:00
Mr Chen 2c87079686 Update system.py 2024-12-18 14:34:28 +08:00
Mr Chen e89785c1d2 Update mw.tpl 2024-12-18 14:13:28 +08:00
Mr Chen 38f8eff1c5 Update mw.tpl 2024-12-18 14:12:07 +08:00
Mr Chen 077394ec99 Update mw.tpl 2024-12-18 14:11:30 +08:00
Mr Chen 7c23f85f75 Update mw.tpl 2024-12-18 14:09:24 +08:00
Mr Chen 20c1ceab92 Merge pull request #647 from midoks/dev
valkey命令加入
2024-12-18 12:21:13 +08:00
Mr Chen e5585caa09 Update version.py 2024-12-18 12:20:42 +08:00
Mr Chen a11b49befe update 2024-12-18 12:17:36 +08:00
Mr Chen 58027e4607 Merge pull request #646 from midoks/dev
valkey插件,redis的平替
2024-12-18 02:14:54 +08:00
Mr Chen 1285641746 Update index.py 2024-12-18 02:02:51 +08:00
Mr Chen 843ac18d2d Update valkey.conf 2024-12-18 01:56:03 +08:00
Mr Chen 4383a202f2 update 2024-12-18 01:55:29 +08:00
Mr Chen cda412f6a9 update 2024-12-18 01:39:54 +08:00
Mr Chen f26b84c799 Update index.py 2024-12-18 01:39:07 +08:00
Mr Chen 2fc3fd3ef1 update 2024-12-18 01:38:22 +08:00
Mr Chen 57d04de8a5 Update redis.js 2024-12-18 01:38:14 +08:00
Mr Chen 3e43c22a42 valkey,redis的平替 2024-12-18 01:33:46 +08:00
Mr Chen ea643b58d8 update 2024-12-18 01:21:14 +08:00
Mr Chen d366490fe5 update 2024-12-18 01:18:45 +08:00
Mr Chen 83093f4c85 Update plugin.py 2024-12-18 01:15:33 +08:00
Mr Chen 99fcfa5223 Merge pull request #645 from midoks/dev
面板安装脚本优化
2024-12-18 00:30:35 +08:00
Mr Chen f6786b367b Update sql_mysql.py 2024-12-18 00:20:40 +08:00
Mr Chen eb373af6ed update 2024-12-18 00:18:18 +08:00
Mr Chen 037e7e907b Update README.md 2024-12-18 00:09:08 +08:00
Mr Chen 80844562e9 Update README.md 2024-12-18 00:07:06 +08:00
Mr Chen 2a935845bf Update README.md 2024-12-17 23:54:44 +08:00
Mr Chen 3acbad4606 Merge pull request #644 from midoks/dev
更改/合并mysql快速安装方式
2024-12-17 23:35:13 +08:00
Mr Chen 1973f6a2b0 删除冗余mysql插件 2024-12-17 23:33:46 +08:00
Mr Chen 85e6a678dd Update sql_mysql.py 2024-12-17 23:20:48 +08:00
Mr Chen 798c52f23d Update sql_mysql.py 2024-12-17 23:18:56 +08:00
Mr Chen aee405f9e2 update 2024-12-17 22:49:01 +08:00
Mr Chen f82ff2d482 Update rhel.sh 2024-12-17 22:46:00 +08:00
Mr Chen d9d9721249 Update index.py 2024-12-17 22:38:37 +08:00
Mr Chen 8ef84763c6 Update index.py 2024-12-17 22:34:35 +08:00
Mr Chen c4f6db4431 update 2024-12-17 22:32:12 +08:00
Mr Chen 60a7e7f885 Update mw.tpl 2024-12-17 22:30:50 +08:00
Mr Chen 7e3c36cd27 Update version.py 2024-12-17 22:25:48 +08:00
Mr Chen 5304abcd00 Update my5.7.cnf 2024-12-17 22:25:00 +08:00
Mr Chen 19d94893cb Update index.py 2024-12-17 22:10:45 +08:00
Mr Chen 485424b5c9 Update version.py 2024-12-17 21:43:17 +08:00
Mr Chen a8af7bed62 Update public.js 2024-12-17 21:42:55 +08:00
Mr Chen f63e7df28d Update public.js 2024-12-17 21:41:58 +08:00
Mr Chen 7e81da6741 Update version.py 2024-12-17 21:37:25 +08:00
Mr Chen 0c8e69c252 Update public.js 2024-12-17 21:36:54 +08:00
Mr Chen da8881dd1e Update version.py 2024-12-17 21:25:47 +08:00
Mr Chen d10c0a2fb9 update 2024-12-17 21:22:40 +08:00
Mr Chen 34ed4b2f25 Update public.js 2024-12-17 21:20:32 +08:00
Mr Chen a109b148f6 Update install_generic.sh 2024-12-17 21:03:11 +08:00
Mr Chen 65c7eeb9c9 update 2024-12-17 20:58:26 +08:00
Mr Chen e45b9b4101 mysql极速办版优化 2024-12-17 20:48:23 +08:00
Mr Chen 8c9bfd7e2d update 2024-12-17 18:03:18 +08:00
Mr Chen 208e418bba Update index_mysql_apt.py 2024-12-17 17:41:59 +08:00
Mr Chen 05278bdacb Update install_generic.sh 2024-12-17 17:38:01 +08:00
Mr Chen 5b11b35d5d Update install_generic.sh 2024-12-17 17:31:21 +08:00
Mr Chen 9f5844c4de Update install_generic.sh 2024-12-17 17:29:31 +08:00
Mr Chen ae888e6d48 Update install_generic.sh 2024-12-17 17:22:16 +08:00
Mr Chen f5b4af6e38 Update install_generic.sh 2024-12-17 17:20:32 +08:00
Mr Chen 84035e0cb1 Update install_generic.sh 2024-12-17 17:18:55 +08:00
Mr Chen 6d5c3e81c8 Update install_generic.sh 2024-12-17 17:17:48 +08:00
Mr Chen 16db84793d update 2024-12-17 17:15:27 +08:00
Mr Chen 8b8a63c352 update 2024-12-17 17:04:50 +08:00
Mr Chen 698cf0d263 update 2024-12-17 17:03:45 +08:00
Mr Chen 6385d49eeb Update install_generic.sh 2024-12-17 17:00:49 +08:00
Mr Chen 43e69909cd update 2024-12-17 16:59:35 +08:00
Mr Chen aeb0f866c8 Update mysql8.4.service.tpl 2024-12-17 16:39:32 +08:00
Mr Chen 3e5c005f25 update_dev 2024-12-17 15:50:31 +08:00
Mr Chen bde27382b7 Update install.sh 2024-12-17 15:40:52 +08:00
Mr Chen c17df789de Merge pull request #643 from midoks/dev
FTP存储空间 插件 修复
2024-12-17 14:12:48 +08:00
Mr Chen ca6a84fec4 Update index.py 2024-12-17 13:54:26 +08:00
Mr Chen 1c952ca4cd update 2024-12-15 04:52:14 +08:00
Mr Chen c2c7073cd9 Create install_debian.sh 2024-12-15 04:44:51 +08:00
Mr Chen 6c84be1a82 Merge pull request #642 from midoks/dev
相关更新
2024-12-15 04:27:12 +08:00
Mr Chen 16c90290f9 Update index.py 2024-12-15 04:22:07 +08:00
Mr Chen cf707df5e0 Update install.sh 2024-12-15 04:20:40 +08:00
Mr Chen 078f1b763b Update install.sh 2024-12-15 04:18:10 +08:00
Mr Chen 6060faa3ac Update install.sh 2024-12-15 04:16:36 +08:00
Mr Chen 5059157515 update 2024-12-15 04:11:42 +08:00
Mr Chen 49924c6b2b update 2024-12-15 04:08:59 +08:00
Mr Chen 6ff1781372 update 2024-12-15 04:01:57 +08:00
Mr Chen 29fd4d5220 Create my9.1.cnf 2024-12-15 03:42:32 +08:00
Mr Chen 484dc13977 Update mw.tpl 2024-12-15 03:40:59 +08:00
Mr Chen 59fc82c788 Create mysql9.1.service.tpl 2024-12-15 03:05:47 +08:00
Mr Chen 9a4c9154f1 update 2024-12-15 03:01:57 +08:00
Mr Chen 9949bb2493 u 2024-12-15 02:22:12 +08:00
Mr Chen 07fc6ac8c4 openssl 2024-12-15 02:18:32 +08:00
Mr Chen 6a93c3e90f Update openssl_10.sh 2024-12-15 02:16:31 +08:00
Mr Chen 7bd88335c4 Update openssl_30.sh 2024-12-15 02:02:14 +08:00
Mr Chen 9893e3bac2 Update index.py 2024-12-15 02:00:51 +08:00
Mr Chen 946e886799 update 2024-12-15 02:00:38 +08:00
Mr Chen b84301debc Update openssl_30.sh 2024-12-15 01:56:43 +08:00
Mr Chen cb5c95ce03 Update index.py 2024-12-15 01:49:06 +08:00
Mr Chen c0a7e1ddba uppdate 2024-12-15 01:42:30 +08:00
Mr Chen 220af054bb Update index.py 2024-12-15 01:33:29 +08:00
Mr Chen a9634f0249 Update index.py 2024-12-15 01:32:43 +08:00
Mr Chen fd77048d4b Update index.py 2024-12-15 01:30:09 +08:00
Mr Chen 40cb632c80 Create my9.1.cnf 2024-12-15 01:23:01 +08:00
Mr Chen 2313af825e update 2024-12-15 01:21:44 +08:00
Mr Chen 762efdaa9a Update install.sh 2024-12-15 01:19:55 +08:00
Mr Chen b58cafb47a Update install.sh 2024-12-15 01:18:22 +08:00
Mr Chen 308d909e72 Update install.sh 2024-12-15 01:17:45 +08:00
Mr Chen c88eb37b1a Update install.sh 2024-12-14 22:16:51 +08:00
Mr Chen e3189d39f4 Update install.sh 2024-12-14 21:55:57 +08:00
Mr Chen de351c7473 Merge pull request #641 from midoks/dev
修复站点备份目录未指定默认值
2024-12-14 18:40:44 +08:00
Mr Chen 9d08b7de34 Update mw.py 2024-12-14 18:35:26 +08:00
Mr Chen 5cf0745da0 Update file.py 2024-12-14 18:26:55 +08:00
Mr Chen 10009b65be Update file.py 2024-12-14 18:19:31 +08:00
Mr Chen 80c1c0b8b4 Merge pull request #640 from midoks/dev
修复站点根目录未指定默认值
2024-12-14 18:08:19 +08:00
Mr Chen 9169d8899f Update mw.py 2024-12-14 18:06:18 +08:00
Mr Chen 5166e05dbe 修复未指定默认值 2024-12-14 18:04:47 +08:00
Mr Chen e6e9dcb48c update 2024-12-14 17:15:20 +08:00
Mr Chen 712550cec8 Merge pull request #639 from midoks/dev
广告变价
2024-12-14 17:13:30 +08:00
Mr Chen f9061088fe update 2024-12-14 17:11:46 +08:00
Mr Chen c53390d038 Merge pull request #638 from midoks/dev
常见优化
2024-12-14 17:04:57 +08:00
Mr Chen 6fb93b19c9 Update info.json 2024-12-14 16:50:36 +08:00
Mr Chen e07e8391e1 Update gdrive.js 2024-12-14 16:05:49 +08:00
Mr Chen ccd8c056b1 Update install.sh 2024-12-14 15:12:17 +08:00
Mr Chen 32ee0cf14c Update install.sh 2024-12-14 15:10:54 +08:00
Mr Chen 9a6c02dd9a Update install.sh 2024-12-14 15:10:31 +08:00
Mr Chen 3dd77715d8 update 2024-12-14 15:09:51 +08:00
Mr Chen 0f99cdb115 Create install.sh 2024-12-14 15:06:45 +08:00
Mr Chen aecd0726e5 Update info.json 2024-12-14 15:05:33 +08:00
Mr Chen 258b3495a1 Update install.sh 2024-12-14 14:56:40 +08:00
Mr Chen eb52d1a79a Update install.sh 2024-12-14 14:54:22 +08:00
Mr Chen 1ad16b2b94 Create install.sh 2024-12-14 14:51:37 +08:00
Mr Chen fc28136936 Update panel_tools.py 2024-12-14 13:01:31 +08:00
Mr Chen 575f3c9ce4 update 2024-12-14 12:47:20 +08:00
Mr Chen 7c9ca83b46 Update install.sh 2024-12-14 12:22:50 +08:00
Mr Chen 0d6c4010ff update 2024-12-14 05:14:12 +08:00
Mr Chen cb6d9762d5 Update setting.py 2024-12-14 05:01:43 +08:00
Mr Chen a4414d2083 Update sql_mysql.py 2024-12-14 04:52:14 +08:00
Mr Chen 5bcae1b00c Update sql_mysql.py 2024-12-14 04:51:09 +08:00
Mr Chen 5c01f36fe7 Update sql_mysql.py 2024-12-14 04:49:44 +08:00
Mr Chen 84b7d1123e Update sql_mysql.py 2024-12-14 04:49:21 +08:00
Mr Chen b819f345cf Merge pull request #637 from midoks/dev
xhprof|安全入口|面板端口命令修复
2024-12-14 02:52:48 +08:00
Mr Chen 5278116f49 update 2024-12-14 02:47:59 +08:00
Mr Chen af36366a89 Update panel_tools.py 2024-12-14 02:41:39 +08:00
Mr Chen cabba7e2d2 Update panel_tools.py 2024-12-14 02:41:29 +08:00
Mr Chen ef6cc77dc2 update 2024-12-14 02:40:12 +08:00
Mr Chen 4b6de5cd9f Update panel_tools.py 2024-12-14 02:34:07 +08:00
Mr Chen 403e35c6c5 Update app_start.php 2024-12-14 02:21:31 +08:00
Mr Chen e1dbdc5886 Update index.py 2024-12-14 01:02:47 +08:00
Mr Chen 9e0a64a51f Update index.py 2024-12-14 01:01:47 +08:00
Mr Chen 971cc3a42a Update index.py 2024-12-14 00:24:59 +08:00
Mr Chen 1c109ee86f Update index.py 2024-12-14 00:24:36 +08:00
Mr Chen b84106ae70 Update index.py 2024-12-14 00:24:23 +08:00
Mr Chen 05881be9b9 Update index.py 2024-12-14 00:23:54 +08:00
Mr Chen 06a7b3da19 Update index.py 2024-12-14 00:20:14 +08:00
Mr Chen 9d77f66e47 update 2024-12-14 00:19:32 +08:00
Mr Chen 85afff4848 Update app_start.php 2024-12-13 23:36:16 +08:00
Mr Chen 8498eaa16d Update app_start.php 2024-12-13 23:28:48 +08:00
Mr Chen 1e78341559 Update index.py 2024-12-13 23:21:05 +08:00
Mr Chen e4ed5a1d19 Update app_start.php 2024-12-13 23:19:00 +08:00
Mr Chen 7b247d1e6f Update index.py 2024-12-13 23:13:46 +08:00
Mr Chen f98a7298c5 update 2024-12-13 23:10:04 +08:00
Mr Chen 8e4e9ddf62 Update index.py 2024-12-13 23:05:31 +08:00
Mr Chen aea7fbe385 Update public.js 2024-12-13 23:05:26 +08:00
Mr Chen 392442b7b7 Merge pull request #636 from midoks/dev
js 兼容mac文件保存命令
2024-12-13 22:29:23 +08:00
Mr Chen cce3102beb Update public.js 2024-12-13 22:25:35 +08:00
Mr Chen fdf2e3854e Update public.js 2024-12-13 22:18:20 +08:00
Mr Chen 95011544c1 Merge pull request #635 from midoks/dev
修复监控设置不生效问题
2024-12-13 21:28:59 +08:00
Mr Chen fc97eb1c14 Update panel_task.py 2024-12-13 20:50:03 +08:00
Mr Chen fc6ec859fe Update panel_task.py 2024-12-13 20:44:50 +08:00
Mr Chen 582ea54ed5 Update panel_task.py 2024-12-13 20:34:36 +08:00
Mr Chen 6caedb5b06 Merge pull request #634 from midoks/dev
gorse安装检测
2024-12-13 03:16:47 +08:00
Mr Chen 307135d495 Update index.py 2024-12-13 03:14:28 +08:00
Mr Chen f786be41e7 Update index.py 2024-12-13 03:13:13 +08:00
Mr Chen e18ae543ee Update index.py 2024-12-13 03:07:26 +08:00
Mr Chen ab606e0629 Update index.py 2024-12-13 02:32:45 +08:00
Mr Chen b6cda24231 Update install.sh 2024-12-13 02:20:25 +08:00
Mr Chen ad4714418d Update install.sh 2024-12-13 02:19:11 +08:00
366 changed files with 19252 additions and 12700 deletions
+4 -2
View File
@@ -176,7 +176,6 @@ plugins/op_auth
plugins/l2tp
plugins/openlitespeed
plugins/tamper_proof
plugins/cryptocurrency_trade
plugins/zimg
plugins/bk_demo
plugins/mail
@@ -189,7 +188,10 @@ plugins/tidb
plugins/goedge-admin
plugins/goedge-node
plugins/goedge-happy
plugins/dztasks
/logs
/data
/plugins/flexcdn
/plugins/tools
/plugins/choose-linux-python
*.md5
+15 -6
View File
@@ -22,7 +22,6 @@
* SSH终端工具
* 面板收藏功能
* 网站子目录绑定
* 网站备份功能
* 插件方式管理
@@ -41,7 +40,7 @@ Talk is cheap, show me the code. -- linus
### 特别赞助
- [找资源 - 阿里云盘资源搜索引擎](https://zhaoziyuan1.cc)
- [虚位以待](https://bbs.midoks.icu)
### 主要插件介绍
@@ -49,8 +48,9 @@ Talk is cheap, show me the code. -- linus
* PHP[53-84] - PHP是世界上最好的编程语言。
* MySQL - 一种关系数据库管理系统。
* MariaDB - 是MySQL的一个重要分支。
* MySQL[APT/YUM] - 一种关系数据库管理系统。
* MySQL[community] - 一种关系数据库管理系统。
* MongoDB - 一种非关系NOSQL数据库管理系统。
* PostgreSQL - 功能强大的开源数据库。
* phpMyAdmin - 著名Web端MySQL管理工具。
* Memcached - 一个高性能的分布式内存对象缓存系统。
* Redis - 一个高性能的KV数据库。
@@ -94,8 +94,6 @@ PHP[72-84]支持phpMyAdmin[5.2.1]
# AD - VPS推荐 - 🙏
- [ZZZ评测](https://www.zzzvps.com/)
| 服务商 | LOGO | 推广地址 | 优惠码 |
| ------------- |----------|-----------|-------|
| digitalvirt |[![digitalvirt](https://digitalvirt.com/templates/BlueWhite/img/logo-dark.svg)](https://digitalvirt.com/aff.php?aff=154) | https://digitalvirt.com/aff.php?aff=154 | mdserver-web |
@@ -187,12 +185,23 @@ curl --insecure -fsSL https://code.midoks.icu/midoks/mdserver-web/raw/branch/dev
curl --insecure -fsSL https://code.midoks.icu/midoks/mdserver-web/raw/branch/dev/scripts/update_dev.sh | bash
```
### 旧版安装
### 旧版安装/更新
```
curl --insecure -fsSL https://raw.githubusercontent.com/midoks/mdserver-web/dev/scripts/old/install.sh | bash
curl --insecure -fsSL https://raw.githubusercontent.com/midoks/mdserver-web/dev/scripts/old/update.sh | bash
```
### 偶然问题
- 在安装/更新时,突然出现python插件pip,psutil,可尝试如下解决方案
```
cd /www/server/mdserver-web rm -rf lib
cd /www/server/mdserver-web && rm -rf lib64
cd /www/server/mdserver-web && rm -rf bin
cd /www/server/mdserver-web && rm -rf include
mw update/mw update_dev
```
### 捐赠地址 USDT(TRC20)
TVbNgrpeGBGZVm5gTLa21ADP7RpnPFhjya
+14 -5
View File
@@ -82,17 +82,26 @@ mw_start_bgtask(){
mw_stop()
{
PLIST=`ps -ef|grep app:app |grep -v grep|awk '{print $2}'`
for i in $PLIST
APP_LIST=`ps -ef|grep app:app |grep -v grep|awk '{print $2}'`
APP_LIST=($APP_LIST)
for p in ${APP_LIST[@]}
do
kill -9 $i > /dev/null 2>&1
kill -9 $p > /dev/null 2>&1
done
PIDS=`ps -ef|grep panel_task.py | grep -v grep |awk '{print $2}'`
for p in $PIDS
TASK_LIST=`ps -ef|grep panel_task.py | grep -v grep |awk '{print $2}'`
TASK_LIST=($TASK_LIST)
for p in ${TASK_LIST[@]}
do
kill -9 $p > /dev/null 2>&1
done
zzpids=`ps -A -o stat,ppid,pid | grep -e '^[Zz]' | awk '{print $2}'`
zzpids=($zzpids)
for p in ${zzpids[@]}
do
kill -9 ${p} > /dev/null 2>&1
done
}
case "$1" in
+4
View File
@@ -4,9 +4,13 @@
- 面板相关命令
```
mw start | 启动面板服务器
mw stop | 停止面板服务器
mw restart | 重启面板服务器
mw default | 显示登录信息
mw db | 快捷连接MySQL
mw redis | 快捷连接Redis
mw valkey | 快捷连接valkey
mw mongodb | 快捷连接MongoDB
mw pgdb | 快捷连接PostgreSQL
----------------------------------------
+3 -1
View File
@@ -140,7 +140,9 @@ def systemTask():
from utils.system import monitor
try:
while True:
monitor.instance().run()
monitor_status = thisdb.getOption('monitor_status',type='monitor',default='open')
if monitor_status == 'open':
monitor.instance().run()
time.sleep(5)
except Exception as ex:
print('systemTask:',mw.getTracebackInfo())
+30 -6
View File
@@ -57,7 +57,9 @@ def mwcli(mw_input=0):
'(2) 停止面板服务',
'(3) 启动面板服务',
'(4) 重载面板服务',
'(5) 修改面板端口',
'(5) 修改面板IP',
'(6) 修改面板端口',
'(7) 关闭安全入口',
'(10) 查看面板默认信息',
'(11) 修改面板密码',
'(12) 修改面板用户名',
@@ -73,6 +75,7 @@ def mwcli(mw_input=0):
'(26) 关闭二次验证',
'(27) 查看防火墙信息',
'(28) 自动识别防火墙端口到面板',
'(29) 自动识别配置站点信息',
'(100) 开启PHP52显示',
'(101) 关闭PHP52显示',
'(200) 切换Linux系统软件源',
@@ -98,8 +101,9 @@ def mwcli(mw_input=0):
mw_input = 0
nums = [
1, 2, 3, 4, 5, 10, 11, 12, 13, 14, 15,
20, 21, 22, 23, 24, 25, 26, 27, 28,
1, 2, 3, 4, 5, 6, 7,
10, 11, 12, 13, 14, 15,
20, 21, 22, 23, 24, 25, 26, 27, 28, 29,
100, 101,
200, 201
]
@@ -117,6 +121,16 @@ def mwcli(mw_input=0):
elif mw_input == 4:
os.system(INIT_CMD + " reload")
elif mw_input == 5:
in_ip = mw_input_cmd("请输入设置的面板IP:")
in_ip = in_ip.strip()
ip_text = panel_dir + '/data/iplist.txt'
if not mw.isVaildIp(in_ip):
mw.echoInfo("【"+in_ip+"】: IP不合法")
return
mw.writeFile(ip_text, in_ip)
thisdb.setOption('server_ip', in_ip)
mw.echoInfo("设置面板IP: " + in_ip)
elif mw_input == 6:
in_port = mw_input_cmd("请输入新的面板端口:")
in_port_int = int(in_port.strip())
if in_port_int < 65536 and in_port_int > 0:
@@ -128,6 +142,9 @@ def mwcli(mw_input=0):
else:
mw.echoInfo("端口范围在0-65536之间")
return
elif mw_input == 7:
thisdb.setOption('admin_path', '')
mw.echoInfo("关闭安全入口成功!")
elif mw_input == 10:
os.system(INIT_CMD + " default")
elif mw_input == 11:
@@ -220,9 +237,12 @@ def mwcli(mw_input=0):
if not run_cmd:
mw.echoInfo("未检测到防火墙!")
elif mw_input == 28:
from utils.firewall import Firewall as MwFirewall
MwFirewall.instance().aIF()
mw.echoInfo("执行自动识别防火墙端口到面板成功!")
elif mw_input == 29:
from utils.site_reflect import parse as MwParse
MwParse()
mw.echoInfo("自动识别配置站点信息成功!")
elif mw_input == 100:
php_conf = panel_dir + '/plugins/php/info.json'
if os.path.exists(php_conf):
@@ -240,7 +260,8 @@ def mwcli(mw_input=0):
mw.writeFile(php_conf, cont)
mw.echoInfo("执行PHP52隐藏成功!")
elif mw_input == 200:
os.system(INIT_CMD + " mirror")
os.system("bash <(curl -sSL https://linuxmirrors.cn/main.sh)")
# os.system(INIT_CMD + " mirror")
elif mw_input == 201:
os.system('curl -Lso- bench.sh | bash')
@@ -283,7 +304,10 @@ def show_panel_pwd():
def show_panel_adminpath():
admin_path = thisdb.getOption('admin_path')
print('/'+admin_path)
if admin_path == '':
print('/login')
else:
print('/'+admin_path)
def set_panel_username(username=None):
@@ -21,8 +21,8 @@ CREATE TABLE IF NOT EXISTS `domain` (
`dnsapi_id` TEXT,
`email` TEXT,
`remark` TEXT,
`effective_date` TEXT,
`expiration_date` TEXT,
`effective_date` TEXT default '',
`expiration_date` TEXT default '',
`error` TEXT,
`status` INTEGER default '0',
`addtime` TEXT
@@ -17,8 +17,16 @@ access_key = "xxx"
# 指定用户
userId = 1
sys.path.append(os.getcwd() + "/class/core")
import mw
if sys.platform != "darwin":
os.chdir("/www/server/mdserver-web")
web_dir = os.getcwd() + "/web"
if os.path.exists(web_dir):
sys.path.append(web_dir)
os.chdir(web_dir)
import core.mw as mw
domain = sys.argv[1]
ssl_path = sys.argv[2]
+18 -15
View File
@@ -186,24 +186,25 @@ def initDreplace():
def apaOp(method):
file = initDreplace()
return 'ok'
current_os = mw.getOs()
if current_os == "darwin":
data = mw.execShell(file + ' ' + method)
if data[1] == '':
return 'ok'
return data[1]
# current_os = mw.getOs()
# if current_os == "darwin":
# data = mw.execShell(file + ' ' + method)
# if data[1] == '':
# return 'ok'
# return data[1]
if current_os.startswith("freebsd"):
data = mw.execShell('service ' + getPluginName() + ' ' + method)
if data[1] == '':
return 'ok'
return data[1]
# if current_os.startswith("freebsd"):
# data = mw.execShell('service ' + getPluginName() + ' ' + method)
# if data[1] == '':
# return 'ok'
# return data[1]
data = mw.execShell('systemctl ' + method + ' ' + getPluginName())
if data[1] == '':
return 'ok'
return data[1]
# data = mw.execShell('systemctl ' + method + ' ' + getPluginName())
# if data[1] == '':
# return 'ok'
# return data[1]
def start():
@@ -600,6 +601,8 @@ def runHookDstDomain(row):
hookWriteLog('开始申请【'+domain+'】SSL证书')
cmd = "#!/bin/bash\n"
cmd += "PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin:/opt/homebrew/bin:/root/.acme.sh\n"
cmd += "export PATH\n"
if mw.isAppleSystem():
user = getRunUser()
+18 -9
View File
@@ -274,7 +274,7 @@ function dnsapiAdd(row){
// console.log(row);
var option_name = '';
var option_remark = '';
var option_type = 'cf';
var option_type = 'dns_cf';
var option_val = '';
var option_id = 0;
if (typeof(row) != 'undefined'){
@@ -286,7 +286,6 @@ function dnsapiAdd(row){
}
// console.log(option_name);
function renderDnsapiOption(name, val){
var vlist = {};
if (val != ''){
@@ -303,18 +302,16 @@ function dnsapiAdd(row){
}
var key = getDnsapiKey(name);
var klist = key.split(':');
// console.log(klist);
var option_html = '';
for (var i = 0; i < klist.length; i++) {
var klist_val = '';
if (klist[i] in vlist){
klist_val = vlist[klist[i]];
}
option_html += "\
<span class='tname'>"+klist[i]+"</span>\
option_html += "<span class='tname'>"+klist[i]+"</span>\
<div class='info-r'>\
<input name='"+klist[i]+"' class='bt-input-text mr5' style='width:100%;' value='"+klist_val+"' placeholder='请输入对应值' type='text'>\
</div>";
@@ -379,7 +376,6 @@ function dnsapiAdd(row){
$('select[name="type"]').html(option);
$('select[name="type"]').change(function(){
var name = $(this).val();
if (option_type == name){
renderDnsapiOption(name, option_val);
} else {
@@ -667,11 +663,24 @@ function domainAdd(row){
var rdata = $.parseJSON(data.data);
for (var i = 0; i < rdata.length; i++) {
if (option_dnsapi_id == rdata[i]['id']){
dnsapi_id_html += "<option value='"+rdata[i]['id']+"' selected>"+rdata[i]['name']+"</option>";
dnsapi_id_html += "<option value='"+rdata[i]['id']+"' val='"+rdata[i]['val']+"' selected>"+rdata[i]['name']+"</option>";
} else {
dnsapi_id_html += "<option value='"+rdata[i]['id']+"'>"+rdata[i]['name']+"</option>";
dnsapi_id_html += "<option value='"+rdata[i]['id']+"' val='"+rdata[i]['val']+"'>"+rdata[i]['name']+"</option>";
}
}
$('select[name="dnsapi_id"]').change(function(){
var val = $('select[name="dnsapi_id"]').find("option:selected").attr('val');
var val_arr = val.split("|");
for (var i = 0; i < val_arr.length; i++) {
var param = val_arr[i];
var strictEmailRegex = /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
if(strictEmailRegex.test(param)){
$('input[name="email"]').val(param);
}
}
});
$('select[name="dnsapi_id"]').html(dnsapi_id_html);
});
},
+14 -6
View File
@@ -6,8 +6,18 @@ import os
import time
import json
sys.path.append(os.getcwd() + "/class/core")
import mw
# print(sys.platform)
if sys.platform != "darwin":
os.chdir("/www/server/mdserver-web")
web_dir = os.getcwd() + "/web"
if os.path.exists(web_dir):
sys.path.append(web_dir)
os.chdir(web_dir)
import core.mw as mw
from utils.crontab import crontab as MwCrontab
app_debug = False
@@ -69,8 +79,6 @@ def createBgTaskByName(name):
if res and res["id"] == args["task_id"]:
print("计划任务已经存在!")
return True
import crontab_api
api = crontab_api.crontab_api()
mw_dir = mw.getPanelDir()
cmd = '''
@@ -99,10 +107,10 @@ logs_file=$plugin_path/${rname}.log
'stype': "toShell",
'sname': '',
'sbody': cmd,
'urladdress': '',
'url_address': '',
}
task_id = api.add(params)
task_id = MwCrontab.instance().add(params)
if task_id > 0:
args["task_id"] = task_id
args["name"] = name
+1 -1
View File
@@ -4,7 +4,7 @@
"name": "alist",
"title": "Alist",
"shell": "install.sh",
"versions":["3.37.4","3.38.0"],
"versions":["3.37.4","3.38.0","3.45.0"],
"tip": "soft",
"checks": "server/alist",
"path": "server/alist",
+1 -1
View File
@@ -23,7 +23,7 @@ app_start(){
app_stop(){
echo "dztasks stopped"
ps -ef| grep alist | grep -v grep | grep -v python | grep -v sh | awk '{print $2}'| xargs kill
ps -ef| grep alist | grep -v grep | grep -v python | grep -v sh | awk '{print $2}'| xargs kill -9
}
+2 -2
View File
@@ -8,7 +8,7 @@ rootPath=$(dirname "$rootPath")
serverPath=$(dirname "$rootPath")
# cd /Users/midoks/Desktop/mwdev/server/mdserver-web/plugins/alist && bash install.sh install 3.37.4
# cd /www/server/mdserver-web/plugins/alist && bash install.sh install 3.37.4
# cd /www/server/mdserver-web/plugins/alist && bash install.sh install 3.45.0
VERSION=$2
@@ -41,7 +41,7 @@ Install_App()
ALIST_DIR=$serverPath/source/alist
if [ ! -f $ALIST_DIR/${FILE_TGZ} ];then
wget -O $ALIST_DIR/${FILE_TGZ} https://github.com/alist-org/alist/releases/download/v${VERSION}/${FILE_TGZ}
wget --no-check-certificate -O $ALIST_DIR/${FILE_TGZ} https://github.com/alist-org/alist/releases/download/v${VERSION}/${FILE_TGZ}
fi
mkdir -p $serverPath/alist
+4 -11
View File
@@ -20,16 +20,6 @@ if os.path.exists(web_dir):
import core.mw as mw
import core.db as db
_ver = sys.version_info
is_py2 = (_ver[0] == 2)
is_py3 = (_ver[0] == 3)
DEBUG = False
if is_py2:
reload(sys)
sys.setdefaultencoding('utf-8')
app_debug = False
if mw.isAppleSystem():
app_debug = True
@@ -81,7 +71,10 @@ def status():
def getConf():
cfg = getServerDir() + "/cfg.json"
if not os.path.exists(cfg):
return mw.returnJson(False, "未配置", [])
rdata = {
'use_sftp':False,
}
return mw.returnJson(False, "未配置", rdata)
data = mw.readFile(cfg)
data = json.loads(data)
return mw.returnJson(True, "OK", data)
+2 -1
View File
@@ -1,4 +1,5 @@
{
"sort":6,
"title":"FTP存储空间",
"hook":["backup"],
"tip":"soft",
@@ -13,5 +14,5 @@
"author":"midoks",
"home":"https://github.com/midoks/mdserver-web",
"date":"2022-10-23",
"pid": "4"
"pid": "5"
}
+3 -1
View File
@@ -131,6 +131,7 @@ def initConf():
"/var/log/wtmp",
"/var/log/secure",
"/var/log/lastlog",
"/var/log/syslog",
"/var/log/cron",
"/www/wwwlogs",
"/www/server/rsyncd",
@@ -156,6 +157,7 @@ def initConf():
"/www/server/redis/data",
"/www/server/alist/data/log",
"/www/server/dztasks/logs",
"/www/server/rsyncd/lsyncd.log"
"/www/server/cron",
]
for i in clogcom:
@@ -241,7 +243,7 @@ def cleanDirLog(path):
def cleanRun():
plugin_dir = getPluginDir()
log_file = getServerDir()+'/clean.log'
cmd = 'python3 '+plugin_dir+'/index.py clean > '+log_file
cmd = 'cd '+mw.getPanelDir()+' && python3 '+plugin_dir+'/index.py clean > '+log_file
os.system(cmd)
return mw.returnJson(True, '执行成功!')
+1
View File
@@ -1,4 +1,5 @@
{
"sort":2,
"title":"日志清理",
"tip":"soft",
"name":"clean",
+78
View File
@@ -0,0 +1,78 @@
# plugins_cryptocurrency_trade
- https://docs.ccxt.com/en/latest/install.html#python-proxies
数字货币量化交易插件
```
cd /www/server/mdserver-web && python3 plugins/cryptocurrency_trade/ccxt/okex/strategy/st_demo.py
python3 plugins/cryptocurrency_trade/ccxt/okex/strategy/st_demo.py
miniconda3
```
# 免费TV策略
https://cn.tradingview.com/scripts/?script_type=strategies
### tradingview pine 指标
```
// This source code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// © TenCloud
//@version=5
indicator("第一个指标",shorttitle = "开心吧")
ema10 = ta.ema(close, 25)
ema100 = ta.ema(close, 100)
l1=plot(ema10, color=color.red,title = "ema10")
l2=plot(ema100,color = color.green, title = "ema100")
buy = ta.crossover(ema10,ema100)
sell = ta.crossunder(ema10,ema100)
plotchar(buy, text = "buy", color=color.green)
plotchar(sell, text="sell", color=color.red)
l_color = ema10>ema100 ? color.green:color.red
fill(l1,l2,color=color.new(l_color,70))
```
### tradingview pine 策略
```
// This source code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// © TenCloud
//@version=5
strategy("第一个指标",shorttitle = "开心吧", overlay = true, initial_capital = 1000)
ema10 = ta.ema(close, 25)
ema100 = ta.ema(close, 100)
l1=plot(ema10, color=color.red,title = "ema10")
l2=plot(ema100,color = color.green, title = "ema100")
buy = ta.crossover(ema10,ema100)
sell = ta.crossunder(ema10,ema100)
if buy
strategy.entry("long1", strategy.long,1)
if sell
strategy.close("long1", qty_percent = 100,comment = "平仓多单")
// plotchar(buy, text = "buy", color=color.green)
// plotchar(sell, text="sell", color=color.red)
// l_color = ema10>ema100 ? color.green:color.red
// fill(l1,l2,color=color.new(l_color,70))
```
@@ -0,0 +1,555 @@
import ccxt
from datetime import datetime
import time
import sys
import json
import os
import glob
import threading
from pprint import pprint
# print(os.getcwd())
sys.path.append(os.getcwd() + "/class/core")
import mw
# cd /www/server/mdserver-web && source bin/activate
# python3 plugins/cryptocurrency_trade/ccxt/public_data/data.py run
# python3 plugins/cryptocurrency_trade/ccxt/public_data/data.py long
# 查看支持的交易所
# print(ccxt.exchanges)
# 代理设置
# exchange = ccxt.poloniex({
# 'proxies': {
# 'http': 'http://127.0.0.1:1088'
# },
# })
# exchange = ccxt.poloniex()
exchange = ccxt.okex()
def getPluginName():
return 'cryptocurrency_trade'
def getPluginDir():
return mw.getPluginDir() + '/' + getPluginName()
def getServerDir():
return mw.getServerDir() + '/' + getPluginName()
def getConfigData():
cfg_path = getServerDir() + "/data.cfg"
if not os.path.exists(cfg_path):
mw.writeFile(cfg_path, '{}')
t = mw.readFile(cfg_path)
return json.loads(t)
def writeLog(log_str):
if __name__ == "__main__":
print(log_str)
log_file = getServerDir() + '/logs/datasource.log'
mw.writeFileLog(log_str, log_file, 1 * 1024 * 1024)
return True
def isSetDbConf():
data = getConfigData()
if 'db' in data:
return True
return False
def beforeDate(day=360):
dd = time.time() - day * 86400
d = datetime.fromtimestamp(dd)
day = d.strftime("%Y-%m-%d")
return day
def getTextTimeShow(time):
d = datetime.fromtimestamp(time)
day = d.strftime("%Y-%m-%d %H:%M:%S")
return day
def isSqlError(mysqlMsg):
# 检测数据库执行错误
mysqlMsg = str(mysqlMsg)
if "MySQLdb" in mysqlMsg:
return mw.returnJson(False, 'MySQLdb组件缺失! <br>进入SSH命令行输入: pip install mysql-python | pip install mysqlclient==2.0.3')
if "2002," in mysqlMsg:
return mw.returnJson(False, '数据库连接失败,请检查数据库服务是否启动!')
if "2003," in mysqlMsg:
return mw.returnJson(False, "Can't connect to MySQL server on '127.0.0.1' (61)")
if "using password:" in mysqlMsg:
return mw.returnJson(False, '数据库密码错误')
if "1045" in mysqlMsg:
return mw.returnJson(False, '连接错误!')
if "SQL syntax" in mysqlMsg:
return mw.returnJson(False, 'SQL语法错误!')
if "Connection refused" in mysqlMsg:
return mw.returnJson(False, '数据库连接失败,请检查数据库服务是否启动!')
if "1133" in mysqlMsg:
return mw.returnJson(False, '数据库用户不存在!')
if "1007" in mysqlMsg:
return mw.returnJson(False, '数据库已经存在!')
return None
def pMysqlDb():
# pymysql
db = mw.getMyORM()
data = getConfigData()
db_data = data['db']
db.setHost(db_data['db_host'])
db.setPort(db_data['db_port'])
db.setUser(db_data['db_user'])
db.setPwd(db_data['db_pass'])
db.setDbName(db_data['db_name'])
return db
def makeInsertSql(table, item):
sql = "insert into " + table
keyStr = '('
valueStr = ' values('
for i in item:
# print i, item[i]
keyStr += '`' + str(i) + '`,'
valueStr += "'" + str(item[i]) + "',"
keyStrLen = len(keyStr)
keyStr = keyStr[0:keyStrLen - 1]
keyStr += ') '
valueStrLen = len(valueStr)
valueStr = valueStr[0:valueStrLen - 1]
valueStr += ') '
sql += keyStr
sql += valueStr
return sql
def makeReplaceSql(table, item):
sql = "replace into " + table
keyStr = '('
valueStr = ' values('
for i in item:
# print i, item[i]
keyStr += '`' + str(i) + '`,'
valueStr += "'" + str(item[i]) + "',"
keyStrLen = len(keyStr)
keyStr = keyStr[0:keyStrLen - 1]
keyStr += ') '
valueStrLen = len(valueStr)
valueStr = valueStr[0:valueStrLen - 1]
valueStr += ') '
sql += keyStr
sql += valueStr
return sql
def makeUpdateSql(table, item, mid):
sql = "update " + table + " set "
keyStr = ''
for i in item:
keyStr += '`' + str(i) + '`=' + "'" + item[i] + "',"
keyStrLen = len(keyStr)
keyStr = keyStr[0:keyStrLen - 1]
sql += keyStr
sql += " where id = '" + str(mid) + "'"
return sql
def dataToDb(table_name, data):
pdb = pMysqlDb()
for i in data:
rdata = {
'addtime': int(i[0] / 1000),
'open': i[1],
'high': i[2],
'low': i[3],
'close': i[4],
'vol': i[5],
}
# sql = """SELECT id FROM %s where addtime='%s' LIMIT 1""" % (
# table_name, rdata['addtime'])
# fdata = pdb.query(sql)
# if fdata:
# print(table_name + ":" + str(rdata['addtime']) + ", old to db ok")
# else:
# isql = makeReplaceSql(table_name, rdata)
# r = pdb.execute(isql)
# print(table_name + ":" + str(rdata['addtime']) + ", go to db ok")
isql = makeReplaceSql(table_name, rdata)
r = pdb.execute(isql)
# print(table_name + ":" + str(rdata['addtime']) + ", go to db ok")
return True
def makeTableName(input_type="btc", input_tf="1m"):
table_name = "ct_%s_%s" % (input_type, input_tf)
return table_name
def isHasTable(input_type="btc", input_tf="1m"):
pdb = pMysqlDb()
# input_type = 'btc'
# input_tf = '1m'
table_name = makeTableName(input_type, input_tf)
mtable = pdb.query("show tables like '%s'" % (table_name,))
if len(mtable) != 0:
return True
return False
def createSql(input_type="btc", input_tf="1m"):
pdb = pMysqlDb()
# input_type = 'btc'
# input_tf = '1m'
table_name = makeTableName(input_type, input_tf)
mtable = pdb.query("show tables like '%s'" % (table_name,))
if len(mtable) != 0:
return True
sql_tpl = getPluginDir() + "/conf/create.sql"
content = mw.readFile(sql_tpl)
content = content.replace("xx1", input_type)
content = content.replace("xx2", input_tf)
res = pdb.execute(content)
# pprint(res)
return True
def getDataFetch(symbol, start_time="2023-3-1", input_tf="1m", limit=500):
start_time = datetime.strptime(start_time, '%Y-%m-%d')
end_time = datetime.strptime(end_time, '%Y-%m-%d')
start_time_stamp = int(time.mktime(start_time.timetuple())) * 1000
data = exchange.fetch_ohlcv(symbol, timeframe=input_tf,
since=start_time_stamp, limit=limit)
return data
def getPointData(symbol, start_time=1677713220000, input_tf="1m", limit=500):
data = exchange.fetch_ohlcv(
symbol, timeframe=input_tf, since=start_time, limit=limit)
return data
def toUnixTimeSecond(tf="1m"):
if tf.find("m") > -1:
v = int(tf.replace("m", ''))
return v * 60
if tf.find("h") > -1:
v = int(tf.replace("h", ''))
return v * 3600
if tf.find("d") > -1:
v = int(tf.replace("d", ''))
return v * 86400
return 0
def findAndUpdateData(tag, input_tf="1m", start_time="2023-1-1", limit=300):
pdb = pMysqlDb()
table_name = makeTableName(tag, input_tf)
sql = 'SELECT addtime FROM ' + table_name + ' order by addtime desc LIMIT 1'
qdata = pdb.query(sql)
start_time = datetime.strptime(start_time, '%Y-%m-%d')
start_time = int(time.mktime(start_time.timetuple())) * 1000
if len(qdata) != 0:
start_time = int(qdata[0]['addtime']) * 1000
pre_time = toUnixTimeSecond(input_tf) * 5 * 1000
start_time = start_time - pre_time
# pprint(start_time)
symbol = tag.upper() + "/USDT"
data = getPointData(symbol, start_time, input_tf, limit)
# pprint(data)
# print("------------lini===========")
# pprint(data[1:])
if len(qdata) == 1:
data = data[1:]
dataToDb(table_name, data)
now = time.strftime("%m/%d %H:%M:%S")
data_len = len(data)
msg_head = now + "|虚拟币:" + tag + ",tf:" + \
input_tf + "!,总数:" + str(data_len)
writeLog(msg_head)
if data_len > 0:
# print("new data time", data[data_len - 1][0])
dt = getTextTimeShow(data[data_len - 1][0] / 1000)
msg = now + "|最新日期:" + dt
writeLog(msg)
table_name = makeTableName(tag, input_tf)
sql = "SELECT addtime FROM " + table_name + \
" order by addtime desc limit 10000,1"
qdata = pdb.query(sql)
if len(qdata) > 0:
print(qdata)
# input_tf_time = toUnixTimeSecond(input_tf)
# now_t = int(time.time())
# del_before_t = now_t - input_tf_time * 1000
sql = "delete from %s where addtime<'%d' " % (
table_name, qdata[0]['addtime'],)
writeLog("删除冗余数据:" + str(sql))
pdb.execute(sql)
return True
def dataToDbTpl(tag='btc', input_tf="1m", start_time="2023-1-1", limit=300):
# tag = "btc"
# tf = "1m"
# start_time = "2023-1-1"
# end_time = "2023-3-2"
symbol = tag.lower() + '/USDT'
if not isHasTable(tag, input_tf):
createSql(tag, input_tf)
data = getDataFetch(symbol, start_time, input_tf, limit)
table_name = makeTableName(tag, input_tf)
dataToDb(table_name, data)
now = time.strftime("%m/%d %H:%M:%S")
data_len = len(data)
writeLog(now + "|数据获取成功!,总数:" + str(data_len))
else:
findAndUpdateData(tag, input_tf, start_time, limit)
return True
def dataToDbList(input_tf="1m", start_time="2023-1-1"):
data = getConfigData()
if not 'token' in data:
writeLog("未设置同步配置,需要添加币种!")
return
for t in data['token']:
dataToDbTpl(t, input_tf, start_time)
time.sleep(4)
def dataRunToDb():
data = getConfigData()
if not 'db' in data:
writeLog("数据库未设置!")
return
tag = "btc"
symbol = tag.upper() + '/USDT'
# pprint(exchange.fetch_ticker('XRP/USDT'))
limit_count = 1
start_time = "2023-1-1"
end_time = "2023-3-2"
tf = "1m"
if not isHasTable(tag, tf):
createSql(tag, tf)
data = getDataFetch(symbol, start_time, end_time, tf, limit_count)
table_name = makeTableName(tag, tf)
dataToDb(table_name, data)
china_datetime = str(datetime.now())
data_len = len(data)
writeLog(china_datetime + ":数据获取成功!,总数:" + str(data_len))
else:
findAndUpdateData(tag, tf, start_time, 30)
return data
def startTask():
# 任务队列
try:
while True:
time.sleep(5)
except Exception as e:
time.sleep(60)
startTask()
def setDaemon(t):
if sys.version_info.major == 3 and sys.version_info.minor >= 10:
t.daemon = True
else:
t.setDaemon(True)
return t
def dataDay():
try:
while True:
if not isSetDbConf():
print("数据库未设置!")
else:
start_time = beforeDate(2 * 365)
dataToDbList("1d", start_time=start_time)
time.sleep(3600)
# time.sleep(10)
except Exception as e:
time.sleep(60)
dataDay()
def data4h():
try:
while True:
if not isSetDbConf():
print("数据库未设置!")
else:
start_time = beforeDate(365)
dataToDbList("4h", start_time=start_time)
time.sleep(10)
except Exception as e:
time.sleep(60)
data4h()
def data1h():
try:
while True:
if not isSetDbConf():
print("数据库未设置!")
else:
start_time = beforeDate(365)
dataToDbList("1h", start_time=start_time)
time.sleep(10)
except Exception as e:
print(e)
time.sleep(60)
data1h()
def data15m():
try:
while True:
if not isSetDbConf():
print("数据库未设置!")
else:
start_time = beforeDate(365)
dataToDbList("15m", start_time=start_time)
time.sleep(10)
except Exception as e:
time.sleep(60)
data15m()
def data5m():
try:
while True:
if not isSetDbConf():
print("数据库未设置!")
else:
start_time = beforeDate(180)
dataToDbList("5m", start_time=start_time)
time.sleep(10)
except Exception as e:
time.sleep(60)
data5m()
def data1m():
try:
while True:
if not isSetDbConf():
print("数据库未设置!")
else:
start_time = beforeDate(30)
dataToDbList("1m", start_time=start_time)
time.sleep(10)
except Exception as e:
time.sleep(60)
data1m()
def longRun():
# 日线
d1_tt = threading.Thread(target=dataDay)
d1_tt = setDaemon(d1_tt)
d1_tt.start()
# 4h
h4_tt = threading.Thread(target=data4h)
h4_tt = setDaemon(h4_tt)
h4_tt.start()
# 1h
h1_tt = threading.Thread(target=data1h)
h1_tt = setDaemon(h1_tt)
h1_tt.start()
# 15m
m15_tt = threading.Thread(target=data15m)
m15_tt = setDaemon(m15_tt)
m15_tt.start()
# 5m
m5_tt = threading.Thread(target=data5m)
m5_tt = setDaemon(m5_tt)
m5_tt.start()
# 1m
# h1m_tt = threading.Thread(target=data1m)
# h1m_tt = setDaemon(h1m_tt)
# h1m_tt.start()
startTask()
def dataRun():
do_num = 0
while True:
if do_num > 1:
break
do_num = do_num + 1
dataRunToDb()
time.sleep(6)
if __name__ == "__main__":
func = sys.argv[1]
if func == 'run':
data5m()()
elif func == 'long':
longRun()
elif func == 'demo':
writeLog('111')
else:
print('error')
@@ -0,0 +1,12 @@
#!/bin/bash
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
export PATH
curPath=`pwd`
# bash plugins/cryptocurrency_trade/ccxt/public_data/data.sh
if [ -f ${curPath}/bin/activate ];then
source ${curPath}/bin/activate
fi
python3 plugins/cryptocurrency_trade/ccxt/public_data/data.py long
@@ -0,0 +1,19 @@
import time
from datetime import datetime
china_datetime = datetime.now()
print(china_datetime)
# date()
tt = time.time() - 180 * 86400
# print(date("%Y-%m-%d", time.time()))
# t = datetime.strptime(str(time.time() - 180 * 86400), "%Y-%m-%d")
# print(t)
d = datetime.fromtimestamp(tt)
# 精确到毫秒
str1 = d.strftime("%Y-%m-%d")
print(str1)
@@ -0,0 +1,352 @@
import ccxt
import time
import sys
import json
import os
import glob
import threading
import pandas as pd
from decimal import Decimal
from pprint import pprint
from datetime import datetime
# print(os.getcwd())
sys.path.append(os.getcwd() + "/class/core")
import mw
exchange = ccxt.poloniex()
def calc_ClosingPriceWithOutStopLossPrice(open_price, stype='buy', profit=0.5):
# profit 百分比 %
v = 0
vf_len = len(str(open_price).split('.')[1])
if stype == 'buy':
v = open_price * (100 + profit) / 100
else:
v = open_price * (100 - profit) / 100
return round(v, vf_len)
def roundVal(price, compare_price):
price = float(price)
csplite = str(compare_price).split('.')
clen = len(csplite)
if clen == 2:
vf_len = len(csplite[1])
return round(price, vf_len)
return price
def roundValCeil(price, compare_price):
price = float(price)
csplite = str(compare_price).split('.')
clen = len(csplite)
if clen == 2:
vf_len = len(csplite[1]) - 1
return round(price, vf_len)
return price
def multiply(a1, a2):
v = Decimal(str(a1)) * Decimal(str(a2))
return v
def addition(a1, a2):
v = Decimal(str(a1)) + Decimal(str(a2))
return v
def subtract(a1, a2):
v = Decimal(str(a1)) - Decimal(str(a2))
return v
def divided(a1, a2):
v = Decimal(str(a1)) / Decimal(str(a2))
return v
def calc_ClosingPrice(open_price, stop_loss_price, stype='buy', profit=0.5):
# profit 百分比 %
v = 0
vf_len = len(str(open_price).split('.')[1])
if stype == 'buy':
v = open_price * (100 + profit) / 100
diff = open_price - stop_loss_price
profit_price = open_price + diff * 1.5
if profit_price > v:
return round(profit_price, vf_len)
else:
v = open_price * (100 - profit) / 100
diff = stop_loss_price - open_price
profit_price = open_price - diff * 1.5
if profit_price < v:
return round(profit_price, vf_len)
return round(v, vf_len)
def toDateFromInt(time_unix, tf_format="%Y-%m-%d %H:%M:%S", time_zone="Asia/Shanghai"):
# 取格式时间
import time
os.environ['TZ'] = time_zone
time_str = time.localtime(time_unix)
time.tzset()
return time.strftime(tf_format, time_str)
def getPluginName():
return 'cryptocurrency_trade'
def getPluginDir():
return mw.getPluginDir() + '/' + getPluginName()
def getServerDir():
return mw.getServerDir() + '/' + getPluginName()
def getConfigData():
cfg_path = getServerDir() + "/data.cfg"
if not os.path.exists(cfg_path):
mw.writeFile(cfg_path, '{}')
t = mw.readFile(cfg_path)
return json.loads(t)
def getUserCfgData():
data = getConfigData()
if 'user' in data:
try:
udata = mw.deDoubleCrypt('mw', data['user'])
udata = json.loads(udata)
return udata
except Exception as e:
pass
return []
def initEx():
data = getUserCfgData()
# print(data)
if (len(data) > 0):
exchange = ccxt.okex({
"apiKey": data['app_key'],
"secret": data['secret'],
"password": data['password'],
})
return exchange
else:
print("初始化失败,检查原因!")
exchange = ccxt.poloniex()
return exchange
def toUnixTimeSecond(tf="1m"):
if tf.find("m") > -1:
v = int(tf.replace("m", ''))
return v * 60
if tf.find("h") > -1:
v = int(tf.replace("h", ''))
return v * 3600
if tf.find("d") > -1:
v = int(tf.replace("d", ''))
return v * 86400
return 0
def notifyMsg(msg, tf='15m', tag='btc'):
trigger_time = toUnixTimeSecond(tf)
return mw.notifyMessage(msg, '量化交易/' + tag, trigger_time)
def makeTableName(input_type="btc", input_tf="1m"):
table_name = "ct_%s_%s" % (input_type, input_tf,)
return table_name
def writeLog(log_str):
if __name__ == "__main__":
print(log_str)
log_file = getServerDir() + '/logs/strategy.log'
mw.writeFileLog(log_str, log_file)
return True
def writeLogEx(log_str, tag='btc'):
tag = tag.replace('/', '_')
# 各种币的详细API日志
if __name__ == "__main__":
print(log_str)
log_file = getServerDir() + '/logs/strategy_' + tag + '.log'
mw.writeFileLog(log_str, log_file)
return True
def writeLogErrorEx(log_str, tag='btc'):
tag = tag.replace('/', '_')
# 各种币的详细API日志
if __name__ == "__main__":
print(log_str)
log_file = getServerDir() + '/logs/strategy_' + tag + '.err.log'
mw.writeFileLog(log_str, log_file)
return True
def pMysqlDb():
# pymysql
db = mw.getMyORM()
data = getConfigData()
db_data = data['db']
# print(db_data)
db.setHost(db_data['db_host'])
db.setPort(db_data['db_port'])
db.setUser(db_data['db_user'])
db.setPwd(db_data['db_pass'])
db.setDbName(db_data['db_name'])
return db
def getOnlineData(symbol, input_tf="15m", limit=200):
bars = exchange.fetch_ohlcv(symbol, timeframe=input_tf, limit=limit)
df = pd.DataFrame(bars[:], columns=['timestamp',
'open', 'high', 'low', 'close', 'volume'])
df['dt'] = pd.to_datetime(df['timestamp'], unit='ms')
return df
def toDataFrame(data):
# print(data)
data = sorted(data, key=lambda x: x["addtime"], reverse=False)
dfield = ['addtime', 'open', 'high', 'low', 'close']
v = {}
for dx in dfield:
v[dx] = []
for x in data:
for i in range(len(x)):
field = dfield[i]
# print(i, field)
v[field].append(x[field])
# pprint(data)
frame = pd.DataFrame(v)
# frame = frame.sort_values(by=['addtime'])
frame['dt'] = pd.to_datetime(frame['addtime'], unit='s')
frame.set_index('dt', inplace=True)
frame.index = frame.index.tz_localize('UTC').tz_convert('Asia/Shanghai')
return frame
def getDataFromDb(tf="1m", tag='btc', limit=1000):
tn = makeTableName(tag, tf)
sql = 'select addtime,open,high,low,close from ' + \
tn + ' order by addtime desc limit ' + str(limit)
pdb = pMysqlDb()
fdata = pdb.query(sql)
# print(fdata)
return fdata
def getDataFromDb_DF(tf="5m", tag='btc', limit=1000):
data = getDataFromDb(tf, tag, limit)
rdata = toDataFrame(data)
return rdata
# 消息模板类
class MsgTpl():
__name = ''
__strategy_name = ''
__time_frame = ''
__content = ''
__open_time = ''
__strategy_dt = ''
__stop_loss_price = ''
__closing_price = ''
__open_price = ''
__msg = ''
def setName(self, name):
self.__name = name
def setStrategyName(self, name):
self.__strategy_name = name
def setTimeFrame(self, tf):
self.__time_frame = tf
def setContent(self, content):
self.__content = content
def setOpenTime(self, time):
self.__open_time = toDateFromInt(time)
def setStrategicDt(self, stype='buy'):
if stype == 'buy':
self.__strategy_dt = '做多'
else:
self.__strategy_dt = '做空'
def setStopLossPrice(self, price):
self.__stop_loss_price = price
def setClosingPrice(self, price):
self.__closing_price = price
def setOpenPrice(self, price):
self.__open_price = price
def setMsg(self, msg):
self.__msg = msg
def toText(self):
msg = ''
msg += '名称:' + self.__name + "\n"
if self.__strategy_name != '':
msg += '策略名称:' + self.__strategy_name + "\n"
if self.__time_frame != '':
msg += '时间周期:' + self.__time_frame + "\n"
if self.__content != '':
msg += '策略描述:' + self.__content + "\n"
if self.__open_time != '':
msg += '开盘时间:' + self.__open_time + "\n"
if self.__strategy_dt != '':
msg += '开仓方向:' + self.__strategy_dt + "\n"
if self.__open_price != '':
msg += '开仓价:' + str(self.__open_price) + "\n"
if self.__stop_loss_price != '':
msg += '止损价:' + str(self.__stop_loss_price) + "\n"
if self.__closing_price != '':
msg += '止盈价:' + str(self.__closing_price) + "\n"
msg += '发送时间:' + mw.getDateFromNow() + "\n"
if self.__msg != '':
msg += __msg
return msg
@@ -0,0 +1,57 @@
# import ccxt
# import talib
import sys
import os
import time
# import pandas as pd
from pprint import pprint
from decimal import Decimal
sys.path.append(os.getcwd() + "/plugins/cryptocurrency_trade/strategy")
import common
# cd /www/server/mdserver-web && source bin/activate
# python3 plugins/cryptocurrency_trade/ccxt/strategy/func_test.py run
# common.notifyMsg("任务开始")
def toUnixTimeSecond(tf="1m"):
if tf.find("m") > -1:
v = int(tf.replace("m", ''))
return v * 60
if tf.find("h") > -1:
v = int(tf.replace("h", ''))
return v * 3600
if tf.find("d") > -1:
v = int(tf.replace("d", ''))
return v * 86400
return 0
def multiply(a1, a2):
v = Decimal(str(a1)) * Decimal(str(a2))
return v
# print(toUnixTimeSecond("1d"))
# f = 19911.2
# s = common.calc_ClosingPrice(f, 19890.2, 'buy')
# print(s)
# print(sys.version_info)
# os.environ['TZ'] = 'Europe/London'
# time.tzset()
# t = time.strftime('%Y-%m-%d %H:%M:%S', time.localtime())
# print(t)
# v = multiply(26236.8, 0.003)
# print(float(v))
# print(v)
print(float('0.00255234') + float('-0.00000255234'))
v1 = common.addition('0.00255234', '-0.00000255234')
print(v1)
@@ -0,0 +1,440 @@
# cd /www/server/mdserver-web && source bin/activate
# python3 plugins/cryptocurrency_trade/ccxt/strategy/gate_100.py run
# python3 plugins/cryptocurrency_trade/ccxt/strategy/gate_100.py long
import ccxt
import talib
import sys
import os
import time
import json
import pandas as pd
# import pandas_ta as ta
from pprint import pprint
import numpy as np
sys.path.append(os.getcwd() + "/plugins/cryptocurrency_trade/strategy")
import common
sys.path.append(os.getcwd() + "/class/core")
import mw
exchange = ccxt.gate({
"apiKey": '756e1ff80526cb0ac9620c75680fc506',
"secret": '95ac89362056bcf12ce37aabff6eb7ec78185483105f39b4a35e8dc8db8b4d3c',
})
exchange.load_markets()
# 默认开仓数据
# default_open_num = 10
default_open = {
"BTC/USDT": 0.01,
'ETH/USDT': 30,
'DOT/USDT': 30,
'CEL/USDT': 30,
}
default_sell = {
"BTC/USDT": 0.01,
'ETH/USDT': 0.01,
'DOT/USDT': 5,
'CEL/USDT': 85,
}
# 做多开仓
def onBuyOrderTry(symbol, stop_loss_price, profit=0.005, timeframe='15m'):
# 信号只在一个周期内执行一次|start
lock_file = common.getServerDir() + '/signal.json'
if not os.path.exists(lock_file):
mw.writeFile(lock_file, '{}')
stype = symbol.replace('/', '_') + '_' + timeframe
trigger_time = common.toUnixTimeSecond(timeframe)
lock_data = json.loads(mw.readFile(lock_file))
if stype in lock_data:
diff_time = time.time() - lock_data[stype]['do_time']
if diff_time >= trigger_time:
lock_data[stype]['do_time'] = time.time()
else:
return False, 0, 0
else:
lock_data[stype] = {'do_time': time.time()}
mw.writeFile(lock_file, json.dumps(lock_data))
# 信号只在一个周期内执行一次|end
common.writeLogEx('------做多----------------------------------', symbol)
default_open_num = default_open[symbol]
# 做多开仓 | 市价
data = exchange.createMarketBuyOrder(
symbol, default_open_num, {"tdMode": "cross"})
common.writeLogEx('开仓数据:', symbol)
common.writeLogEx(json.dumps(data), symbol)
order_id = data['info']['ordId']
order_data = exchange.fetchOrder(order_id, symbol)
common.writeLogEx('订单数据:', symbol)
common.writeLogEx(json.dumps(order_data), symbol)
# 实际开场平均价
open_price = order_data['info']['avgPx']
# 做多-止损价大于开仓价,重设止损价
if float(stop_loss_price) <= float(open_price):
stop_loss_price = float(open_price) * float((1 - 0.003))
# property_val = float(order_data['info']['accFillSz']) + float(order_data['info']['fee'])
property_val = common.addition(
order_data['info']['accFillSz'], order_data['info']['fee'])
property_val = float(property_val)
# 可平仓的数量
property_val = common.roundValCeil(
property_val, order_data['info']['accFillSz'])
common.writeLogEx('可平仓资产:' + str(property_val), symbol)
# 止盈价
diff = float(open_price) - float(stop_loss_price)
closing_price_c = float(open_price) + (diff * 2)
closing_price = float(open_price) * float((1 + profit))
# 选择盈利多的
if closing_price_c > closing_price:
closing_price = closing_price_c
closing_price = common.roundVal(closing_price, stop_loss_price)
# stop_loss_price = common.roundVal(stop_loss_price, open_price)
common.writeLogEx('实际开仓价:' + str(open_price), symbol)
common.writeLogEx('止盈价:' + str(closing_price), symbol)
common.writeLogEx('止损价:' + str(stop_loss_price), symbol)
# 设置 - 止损价/止盈价
sl_exchange_params = {
'ccy': "USDT",
'reduceOnly': True,
'tdMode': "cross",
'slOrdPx': "-1",
'slTriggerPx': stop_loss_price,
}
# 止损条件单
common.writeLogEx('止损参数:' + json.dumps([symbol, 'limit', 'sell',
property_val, stop_loss_price, sl_exchange_params]), symbol)
sl_cond_data = exchange.create_order(
symbol, 'limit', 'sell', property_val, stop_loss_price, sl_exchange_params)
common.writeLogEx('止损价数据:', symbol)
common.writeLogEx(json.dumps(sl_cond_data), symbol)
# 止赢条件单
tp_exchange_params = {
'ccy': "USDT",
'reduceOnly': True,
'tdMode': "cross",
'tpOrdPx': "-1",
'tpTriggerPx': closing_price,
}
common.writeLogEx('止盈参数:' + json.dumps([symbol, 'limit', 'sell',
property_val, closing_price, tp_exchange_params]), symbol)
tp_cond_data = exchange.create_order(
symbol, 'limit', 'sell', property_val, closing_price, tp_exchange_params)
common.writeLogEx('止赢数据:', symbol)
common.writeLogEx(json.dumps(tp_cond_data), symbol)
common.writeLogEx('------做多 end----------------------------------', symbol)
return True, open_price, closing_price
def onBuyOrder(symbol, stop_loss_price, profit=0.005, timeframe='15m'):
# 做多开仓
# profit 百分比
try:
return onBuyOrderTry(symbol, stop_loss_price, profit, timeframe)
except Exception as e:
common.writeLogErrorEx(mw.getTracebackInfo(), symbol)
return False, 0, 0
def onSellOrderTry(symbol, stop_loss_price, profit=0.005, timeframe='15m'):
# 信号只在一个周期内执行一次|start
lock_file = common.getServerDir() + '/signal.json'
if not os.path.exists(lock_file):
mw.writeFile(lock_file, '{}')
stype = symbol.replace('/', '_') + '_' + timeframe
trigger_time = common.toUnixTimeSecond(timeframe)
lock_data = json.loads(mw.readFile(lock_file))
if stype in lock_data:
diff_time = time.time() - lock_data[stype]['do_time']
if diff_time >= trigger_time:
lock_data[stype]['do_time'] = time.time()
else:
return False, 0, 0
else:
lock_data[stype] = {'do_time': time.time()}
mw.writeFile(lock_file, json.dumps(lock_data))
# 信号只在一个周期内执行一次|end
common.writeLogEx('------做空----------------------------------', symbol)
# 计算借币卖币多多少,以USDT为基准
# sell_num = float(default_open_num) / float(stop_loss_price)
# sell_num = round(sell_num, 8)
sell_num = default_sell[symbol]
# 做空开仓 | 市价
data = exchange.createMarketSellOrder(
symbol, sell_num, {"tdMode": "cross", 'ccy': "USDT"})
common.writeLogEx('开仓数据:', symbol)
common.writeLogEx(json.dumps(data), symbol)
order_id = data['info']['ordId']
order_data = exchange.fetchOrder(order_id, symbol)
common.writeLogEx('订单数据:', symbol)
common.writeLogEx(json.dumps(order_data), symbol)
# 实际开场平均价
open_price = order_data['info']['avgPx']
common.writeLogEx('可平仓资产:' + str(sell_num), symbol)
# 做空-止损价小于开仓价,重设止损价
if float(stop_loss_price) <= float(open_price):
stop_loss_price = float(open_price) * float((1 + 0.003))
# 止盈价
diff = float(stop_loss_price) - float(open_price)
closing_price_c = float(open_price) - (diff * 2)
closing_price = float(open_price) * float((1 - profit))
# 选择盈利多的
if closing_price_c < closing_price:
closing_price = closing_price_c
closing_price = common.roundVal(closing_price, open_price)
stop_loss_price = common.roundVal(stop_loss_price, open_price)
common.writeLogEx('实际开仓价:' + str(open_price), symbol)
common.writeLogEx('止盈价:' + str(closing_price), symbol)
common.writeLogEx('止损价:' + str(stop_loss_price), symbol)
# 设置 - 止损价
sl_exchange_params = {
'ccy': "USDT",
'reduceOnly': True,
'tdMode': "cross",
'slOrdPx': "-1",
'slTriggerPx': stop_loss_price,
}
sl_amount = common.multiply(stop_loss_price, sell_num)
# 解决平仓时,未全部平仓
sl_amount = common.addition(sl_amount, 0.1)
common.writeLogEx('止损总价值:' + str(sl_amount), symbol)
common.writeLogEx('止损参数:' + json.dumps([symbol, 'limit', 'buy', float(
sl_amount), stop_loss_price, sl_exchange_params]), symbol)
sl_cond_data = exchange.create_order(
symbol, 'limit', 'buy', sl_amount, stop_loss_price, sl_exchange_params)
common.writeLogEx('止损价数据:', symbol)
common.writeLogEx(json.dumps(sl_cond_data), symbol)
tp_exchange_params = {
'ccy': "USDT",
'reduceOnly': True,
'tdMode': "cross",
'tpOrdPx': "-1",
'tpTriggerPx': closing_price,
}
# 设置 -止盈价
tp_amount = common.multiply(closing_price, sell_num)
# 解决平仓时,未全部平仓
tp_amount = common.addition(tp_amount, 0.1)
common.writeLogEx('止盈总价值:' + str(tp_amount), symbol)
common.writeLogEx('止盈参数:' + json.dumps([symbol, 'limit', 'buy', float(
tp_amount), closing_price, tp_exchange_params]), symbol)
tp_cond_data = exchange.create_order(
symbol, 'limit', 'buy', tp_amount, closing_price, tp_exchange_params)
common.writeLogEx('止盈价数据:', symbol)
common.writeLogEx(json.dumps(tp_cond_data), symbol)
common.writeLogEx('------做空 end----------------------------------', symbol)
return True, open_price, closing_price
def onSellOrder(symbol, stop_loss_price, profit=0.005, timeframe='15m'):
# 做空开仓
# profit 百分比
try:
return onSellOrderTry(symbol, stop_loss_price, profit, timeframe)
except Exception as e:
common.writeLogErrorEx(mw.getTracebackInfo(), symbol)
return False, 0, 0
def getOnlineData(symbol, input_tf="15m", limit=230):
bars = exchange.fetch_ohlcv(symbol, timeframe=input_tf, limit=limit)
df = pd.DataFrame(bars[:], columns=['timestamp',
'open', 'high', 'low', 'close', 'volume'])
df['dt'] = pd.to_datetime(df['timestamp'], unit='ms')
df.set_index('dt', inplace=True)
df.index = df.index.tz_localize('UTC').tz_convert('Asia/Shanghai')
return df
def isKdj(last, last_pre):
# 判断是否是金叉
if (float(last_pre['macd']) < 0) and (float(last['macd']) > 0):
return True
return False
def isDeadFork(last, last_pre):
# 判断是否是死叉
if (float(last_pre['macd']) > 0) and (float(last['macd']) < 0):
return True
return False
def getMACD(df, lenght=-60):
if len(df['close'].values) < 100:
return False, None
close_p = df['close'].values
df['dif'], df['dea'], df['macd'] = talib.MACD(close_p,
fastperiod=12,
slowperiod=26,
signalperiod=9)
return df[lenght:]
def getEMA(df):
close_p = df['close'].values
df['ema'] = talib.EMA(np.array(close_p), timeperiod=200)
return df
def doneMacd(data, tag, timeframe):
data = getEMA(data)
ma_data = getMACD(data)
# alen = len(data)
# print(ma_data)
t_data = ma_data.tail(3)
print(t_data)
last_pre = t_data.iloc[0]
last = t_data.iloc[1]
print(last)
# print(last.index)
# print('close:', last['close'], 'ema:', last['ema'])
obj = common.MsgTpl()
symbol = tag.upper() + '/USDT'
obj.setName(symbol)
obj.setStrategyName("MACD检查")
obj.setTimeFrame(timeframe)
obj.setOpenTime(last['timestamp'] / 1000)
now_data = t_data.iloc[2]
# print('now_data:', now_data)
# msg = obj.toText()
# print(msg)
if isKdj(last, last_pre) and last['close'] > last['ema']:
# if isKdj(last, last_pre):
# closing_price = common.calc_ClosingPrice(
# now_data['close'], last_pre['low'], 'buy')
# # print('closing_price:', closing_price)
# 做多止损点
stop_loss_price = last_pre['low']
buy_status, open_price, closing_price = onBuyOrder(
symbol, stop_loss_price, 0.005, timeframe)
if buy_status:
obj.setStrategicDt('buy')
# 做多止损点
obj.setStopLossPrice(str(stop_loss_price))
obj.setOpenPrice(str(open_price))
obj.setClosingPrice(str(closing_price))
obj.setContent("检查到金叉状态")
msg = obj.toText()
print(msg)
common.notifyMsg(msg, timeframe, tag)
common.writeLog(msg)
if isDeadFork(last, last_pre) and last['close'] < last['ema']:
# if isDeadFork(last, last_pre):
# closing_price = common.calc_ClosingPrice(
# now_data['close'], last_pre['high'], 'sell')
# 做空止损点
stop_loss_price = last_pre['high']
sell_status, open_price, closing_price = onSellOrder(
symbol, stop_loss_price, 0.005, timeframe)
if sell_status:
obj.setStopLossPrice(str(stop_loss_price))
obj.setOpenPrice(str(open_price))
obj.setClosingPrice(str(closing_price))
obj.setStrategicDt('sell')
obj.setContent("检查到死叉状态")
msg = obj.toText()
print(msg)
common.notifyMsg(msg, timeframe, tag)
common.writeLog(msg)
def mainProcess(tag, timeframe='15m'):
symbol = tag.upper() + '/USDT'
data = getOnlineData(symbol, timeframe)
doneMacd(data, tag, timeframe)
def foreachList():
tag_list = ['btc']
for tag in tag_list:
mainProcess(tag, '15m')
time.sleep(1)
def longRun():
while True:
foreachList()
time.sleep(3)
def debug():
while True:
mainProcess('xrp', '1m')
time.sleep(3)
if __name__ == "__main__":
func = sys.argv[1]
if func == 'long':
longRun()
elif func == 'run':
debug()
else:
print('error')
@@ -0,0 +1,138 @@
import ccxt
import talib
import sys
import os
import time
import pandas as pd
import pandas_ta as ta
from pprint import pprint
sys.path.append(os.getcwd() + "/plugins/cryptocurrency_trade/strategy")
import common
# cd /www/server/mdserver-web && source bin/activate
# python3 plugins/cryptocurrency_trade/ccxt/strategy/hammer_robot.py run
pd.set_option('display.max_rows', None)
exchange = common.initEx()
exchange.load_markets()
entry_rsi = 30
exit_rsi = 40
symbol = 'XRP/USDT'
timeframe = '15m'
tf_mult = exchange.parse_timeframe(timeframe) * 1000
def indicators(data):
data['rsi'] = data.ta.rsi(length=10)
data['ema'] = data.ta.ema(length=200)
# close_p = data['close'].values
# data['rsi'] = talib.RSI(close_p, timeperiod=10)
# data['ema'] = talib.EMA(close_p, timeperiod=200)
return data
def check_buy_sell_signals(df):
last_row_index = len(df.index) - 1
lastest_rsi = round(df['rsi'].iloc[-1], 2)
lastest_price = round(df['close'].iloc[-1], 5)
lastest_ema = round(df['ema'].iloc[-1], 5)
lastest_ts = df['timestamp'].iloc[-1]
msg = "lastest_rsi:" + str(lastest_rsi) + " < entry_rsi:" + str(entry_rsi)
msg += ",lastest_price:" + \
str(lastest_price) + " > lastest_ema:" + str(lastest_ema)
print(msg)
long_cond = (lastest_rsi < entry_rsi) and (lastest_price > lastest_ema)
if long_cond:
print("买入")
order = exchange.create_market_buy_order(symbol, 1)
closed_orders = exchange.fetchClosedOrders(symbol, limit=2)
if len(closed_orders) > 0:
print("closed_orders:", closed_orders)
most_recent_closed_order = closed_orders[-1]
diff = lastest_ts - most_recent_closed_order['timestamp']
last_buy_signal_cnt = int(diff / tf_mult)
exit_cond = (lastest_rsi > exit_rsi) and (last_buy_signal_cnt > 10)
if exit_cond:
print("卖出")
order = exchange.create_market_sell_order(symbol, 1)
return
def get_hammer(df, lenght):
# 影线要大于body的多少倍
factor = 2
hl_range = df['high'] - df['low']
body_hi = df.apply(lambda x: max(x['close'], x['open']), axis=1)
body_lo = df.apply(lambda x: min(x['close'], x['open']), axis=1)
body = body_hi - body_lo
body_avg = ta.ema(body, lenght=lenght)
small_body = body < body_avg
# 上下影线站body的百分比
shadow_percent = 10
# 上影线
up_shadow = df['high'] - body_hi
dn_shadow = body_lo - df['low']
has_up_shadow = up_shadow > shadow_percent / 100 * body
has_dn_shadow = dn_shadow > shadow_percent / 100 * body
downtrend = df['close'] < ta.ema(df['close'], 50)
bullish_hammer = downtrend & small_body & (body > 0) & (
dn_shadow >= factor * body) & (has_up_shadow == False)
return bullish_hammer
def runBot():
bars = exchange.fetch_ohlcv(symbol, timeframe=timeframe, limit=200)
df = pd.DataFrame(bars[:], columns=['timestamp',
'open', 'high', 'low', 'close', 'volume'])
# format='%Y-%m-%d %H:%M:%S',
df['dt'] = pd.to_datetime(
df['timestamp'], unit="ms")
df['hammer'] = get_hammer(df, 10)
lastest_hammer = df.iloc[-1, -1]
lastest_price = df.iloc[-1, 0]
print("lastest_price:" + str(lastest_price))
print("lastest_hammer:" + str(lastest_hammer))
print(df.tail())
if lastest_hammer:
print("购买,做多")
notifyMsg("购买,做多")
def longRunBot():
common.notifyMsg("任务开始")
while True:
runBot()
time.sleep(10)
if __name__ == "__main__":
func = sys.argv[1]
if func == 'run':
longRunBot()
else:
print('error')
@@ -0,0 +1,33 @@
[
{
"id":"01",
"name": "MACD-KDJ策略检测|1h",
"file": "macd_kdj.py"
},
{
"id":"02",
"name": "通知测试|60s",
"file": "notify_demo.py"
},
{
"id":"03",
"name": "okex|macd交易策略|15m",
"file": "online_macd_trade.py"
},
{
"id":"04",
"name": "okex|动量交易策略|5m",
"file": "momentun_trade.py"
},
{
"id":"05",
"name": "gate.io|动量交易策略|5m",
"file": "gate_100.py"
},
{
"id":"06",
"name": "仅提醒|Vega交易策略|5m",
"file": "vega_trade.py"
}
]
@@ -0,0 +1,121 @@
# cd /www/server/mdserver-web && source bin/activate
# python3 plugins/cryptocurrency_trade/ccxt/strategy/macd_kdj.py run
# python3 plugins/cryptocurrency_trade/ccxt/strategy/macd_kdj.py long
import ccxt
import talib
import pandas as pd
import time
import sys
import os
from pprint import pprint
sys.path.append(os.getcwd() + "/plugins/cryptocurrency_trade/strategy")
import common
sys.path.append(os.getcwd() + "/class/core")
import mw
pd.set_option('display.max_rows', None)
# import warnings
# warnings.filterwarnings('error')
def getMACD(df, lenght=-60):
if len(df['close'].values) < 100:
return False, None
close_p = df['close'].values
df['dif'], df['dea'], df['macd'] = talib.MACD(close_p,
fastperiod=12,
slowperiod=26,
signalperiod=9)
return True, df[lenght:]
def isKdj(last, last_pre):
# 判断是否是金叉
if (float(last_pre['macd']) < 0) and (float(last['macd']) > 0):
return True
return False
def isDeadFork(last, last_pre):
# 判断是否是死叉
if (float(last_pre['macd']) > 0) and (float(last['macd']) < 0):
return True
return False
def checkData():
tag = 'btc'
tf_frame = '1h'
data = common.getDataFromDb_DF(tf_frame, tag, 300)
# print(data)
b, r = getMACD(data)
if b:
# rlen = len(r)
# r = r.copy()
# r['dt'] = pd.to_datetime(
# r['addtime'], unit='s')
# r['dt'] = r['dt'].dt.tz_convert('Asia/Shanghai')
# print(r)
rlen = len(r)
t_data = r.tail(2)
# print(r.tail(2))
last_pre = t_data.iloc[0]
last = t_data.iloc[1]
# print(last_pre)
# print(last)
# print(last_pre['addtime'])
# print(last_pre['open'])
# print(last_pre['high'])
# print(last_pre['low'])
# print(last_pre['close'])
# print(last['addtime'])
# print(last['open'])
# print(last['high'])
# print(last['low'])
# print(last['close'])
now = mw.getDateFromNow()
if isKdj(last, last_pre):
msg = now + "|{}|{}|检查到金叉状态!".format(tag, tf_frame)
common.notifyMsg(msg, tf_frame, tag)
common.writeLog(msg)
if isDeadFork(last, last_pre):
msg = now + "|{}|{}|检查到死叉状态!".format(tag, tf_frame)
common.notifyMsg(msg, tf_frame, tag)
common.writeLog(msg)
def run():
checkData()
def longRun():
while True:
checkData()
time.sleep(3)
if __name__ == "__main__":
func = sys.argv[1]
if func == 'run':
run()
elif func == 'long':
longRun()
else:
print('error')
@@ -0,0 +1,505 @@
# cd /www/server/mdserver-web && source bin/activate
# python3 plugins/cryptocurrency_trade/ccxt/strategy/momentun_trade.py run
# python3 plugins/cryptocurrency_trade/ccxt/strategy/momentun_trade.py long
# 动量策略交易
import ccxt
import talib
import sys
import os
import time
import json
import pandas as pd
# import pandas_ta as ta
from pprint import pprint
import numpy as np
sys.path.append(os.getcwd() + "/plugins/cryptocurrency_trade/strategy")
import common
sys.path.append(os.getcwd() + "/class/core")
import mw
exchange = common.initEx()
exchange.load_markets()
# 默认开仓数据
# default_open_num = 70
# default_sell_num = 0.003
default_open = {
'BTC/USDT': 30,
'XRP/USDT': 30,
}
default_sell = {
'BTC/USDT': 0.001,
'XRP/USDT': 100,
}
# 做多开仓
def onBuyOrderTry(symbol, stop_loss_price, profit=0.005, timeframe='15m'):
# 信号只在一个周期内执行一次|start
lock_file = common.getServerDir() + '/signal.json'
if not os.path.exists(lock_file):
mw.writeFile(lock_file, '{}')
stype = symbol.replace('/', '_') + '_' + timeframe
trigger_time = common.toUnixTimeSecond(timeframe)
lock_data = json.loads(mw.readFile(lock_file))
if stype in lock_data:
diff_time = time.time() - lock_data[stype]['do_time']
if diff_time >= trigger_time:
lock_data[stype]['do_time'] = time.time()
else:
return False, 0, 0
else:
lock_data[stype] = {'do_time': time.time()}
mw.writeFile(lock_file, json.dumps(lock_data))
# 信号只在一个周期内执行一次|end
common.writeLogEx('------做多----------------------------------', symbol)
default_open_num = default_open[symbol]
# 做多开仓 | 市价
data = exchange.createMarketBuyOrder(
symbol, default_open_num, {"tdMode": "cross"})
common.writeLogEx('开仓数据:', symbol)
common.writeLogEx(json.dumps(data), symbol)
order_id = data['info']['ordId']
order_data = exchange.fetchOrder(order_id, symbol)
common.writeLogEx('订单数据:', symbol)
common.writeLogEx(json.dumps(order_data), symbol)
# 实际开场平均价
open_price = order_data['info']['avgPx']
# 修正小数点位数
open_price = common.roundVal(open_price, stop_loss_price)
common.writeLogEx('实际开仓价:' + str(open_price), symbol)
# 做多-止损价大于开仓价,重设止损价
if float(stop_loss_price) <= float(open_price):
stop_loss_price = float(open_price) * float((1 - 0.003))
# property_val = float(order_data['info']['accFillSz']) + float(order_data['info']['fee'])
property_val = common.addition(order_data['info'][
'accFillSz'], order_data['info']['fee'])
property_val = float(property_val)
# 可平仓的数量
# property_val = common.roundValCeil(
# property_val, order_data['info']['accFillSz'])
common.writeLogEx('可平仓资产:' + str(property_val), symbol)
# 止盈价
diff = float(open_price) - float(stop_loss_price)
closing_price = float(open_price) + (diff * 1.5)
# closing_price = float(open_price) * float((1 + profit))
# # 选择盈利多的
# if closing_price_c > closing_price:
# closing_price = closing_price_c
closing_price = common.roundVal(closing_price, open_price)
stop_loss_price = common.roundVal(stop_loss_price, open_price)
common.writeLogEx('止盈价:' + str(closing_price), symbol)
common.writeLogEx('止损价:' + str(stop_loss_price), symbol)
# 设置 - 止损价/止盈价
sl_exchange_params = {
'ccy': "USDT",
'reduceOnly': True,
'tdMode': "cross",
'slOrdPx': "-1",
'slTriggerPx': stop_loss_price,
}
# 止损条件单
common.writeLogEx('止损参数:' + json.dumps([symbol, 'limit', 'sell',
property_val, stop_loss_price, sl_exchange_params]), symbol)
sl_cond_data = exchange.create_order(
symbol, 'limit', 'sell', property_val, stop_loss_price, sl_exchange_params)
common.writeLogEx('止损价数据:', symbol)
common.writeLogEx(json.dumps(sl_cond_data), symbol)
# 止赢条件单
tp_exchange_params = {
'ccy': "USDT",
'reduceOnly': True,
'tdMode': "cross",
'tpOrdPx': "-1",
'tpTriggerPx': closing_price,
}
common.writeLogEx('止盈参数:' + json.dumps([symbol, 'limit', 'sell',
property_val, closing_price, tp_exchange_params]), symbol)
tp_cond_data = exchange.create_order(
symbol, 'limit', 'sell', property_val, closing_price, tp_exchange_params)
common.writeLogEx('止盈数据:', symbol)
common.writeLogEx(json.dumps(tp_cond_data), symbol)
common.writeLogEx('------做多 end----------------------------------', symbol)
return True, open_price, closing_price
def onBuyOrder(symbol, stop_loss_price, profit=0.005, timeframe='15m'):
# 做多开仓
# profit 百分比
try:
return onBuyOrderTry(symbol, stop_loss_price, profit, timeframe)
except Exception as e:
common.writeLogErrorEx(mw.getTracebackInfo(), symbol)
return False, 0, 0
def onSellOrderTry(symbol, stop_loss_price, profit=0.005, timeframe='15m'):
# 信号只在一个周期内执行一次|start
lock_file = common.getServerDir() + '/signal.json'
if not os.path.exists(lock_file):
mw.writeFile(lock_file, '{}')
stype = symbol.replace('/', '_') + '_' + timeframe
trigger_time = common.toUnixTimeSecond(timeframe)
lock_data = json.loads(mw.readFile(lock_file))
if stype in lock_data:
diff_time = time.time() - lock_data[stype]['do_time']
if diff_time >= trigger_time:
lock_data[stype]['do_time'] = time.time()
else:
return False, 0, 0
else:
lock_data[stype] = {'do_time': time.time()}
mw.writeFile(lock_file, json.dumps(lock_data))
# 信号只在一个周期内执行一次|end
common.writeLogEx('------做空----------------------------------', symbol)
# 计算借币卖币多多少,以USDT为基准
# sell_num = float(default_open_num) / float(stop_loss_price)
# sell_num = round(sell_num, 8)
# sell_num = default_sell_num
sell_num = default_sell[symbol]
# 做空开仓 | 市价
data = exchange.createMarketSellOrder(
symbol, sell_num, {"tdMode": "cross", 'ccy': "USDT"})
common.writeLogEx('开仓数据:', symbol)
common.writeLogEx(json.dumps(data), symbol)
order_id = data['info']['ordId']
order_data = exchange.fetchOrder(order_id, symbol)
common.writeLogEx('订单数据:', symbol)
common.writeLogEx(json.dumps(order_data), symbol)
# 实际开场平均价
open_price = order_data['info']['avgPx']
# 修正
open_price = common.roundVal(open_price, stop_loss_price)
common.writeLogEx('实际开仓价:' + str(open_price), symbol)
common.writeLogEx('可平仓资产:' + str(sell_num), symbol)
# 做空-止损价小于开仓价,重设止损价
if float(stop_loss_price) <= float(open_price):
stop_loss_price = float(open_price) * float((1 + 0.003))
# 止盈价
diff = float(stop_loss_price) - float(open_price)
closing_price = float(open_price) - (diff * 1.5)
# closing_price = float(open_price) * float((1 - profit))
# 选择盈利多的
# if closing_price_c < closing_price:
# closing_price = closing_price_c
closing_price = common.roundVal(closing_price, open_price)
stop_loss_price = common.roundVal(stop_loss_price, open_price)
common.writeLogEx('止盈价:' + str(closing_price), symbol)
common.writeLogEx('止损价:' + str(stop_loss_price), symbol)
# 设置 - 止损价
sl_exchange_params = {
'ccy': "USDT",
'reduceOnly': True,
'tdMode': "cross",
'slOrdPx': "-1",
'slTriggerPx': stop_loss_price,
}
sl_amount = common.multiply(stop_loss_price, sell_num)
# 解决平仓时,未全部平仓
sl_amount = common.addition(sl_amount, 0.1)
common.writeLogEx('止损总价值:' + str(sl_amount), symbol)
common.writeLogEx('止损参数:' + json.dumps([symbol, 'limit', 'buy', float(
sl_amount), stop_loss_price, sl_exchange_params]), symbol)
sl_cond_data = exchange.create_order(
symbol, 'limit', 'buy', float(sl_amount), stop_loss_price, sl_exchange_params)
common.writeLogEx('止损价数据:', symbol)
common.writeLogEx(json.dumps(sl_cond_data), symbol)
tp_exchange_params = {
'ccy': "USDT",
'reduceOnly': True,
'tdMode': "cross",
'tpOrdPx': "-1",
'tpTriggerPx': closing_price,
}
# 设置 -止盈价
# tp_amount = closing_price * sell_num
tp_amount = common.multiply(closing_price, sell_num)
# 解决平仓时,未全部平仓
tp_amount = common.addition(tp_amount, 0.1)
common.writeLogEx('止盈总价值:' + str(tp_amount), symbol)
common.writeLogEx('止盈参数:' + json.dumps([symbol, 'limit', 'buy', float(
tp_amount), closing_price, tp_exchange_params]), symbol)
tp_cond_data = exchange.create_order(
symbol, 'limit', 'buy', float(tp_amount), closing_price, tp_exchange_params)
common.writeLogEx('止盈价数据:', symbol)
common.writeLogEx(json.dumps(tp_cond_data), symbol)
common.writeLogEx('------做空 end----------------------------------', symbol)
return True, open_price, closing_price
def onSellOrder(symbol, stop_loss_price, profit=0.005, timeframe='15m'):
# 做空开仓
# profit 百分比
try:
return onSellOrderTry(symbol, stop_loss_price, profit, timeframe)
except Exception as e:
common.writeLogErrorEx(mw.getTracebackInfo(), symbol)
return False, 0, 0
def getOnlineData(symbol, input_tf="15m", limit=230):
bars = exchange.fetch_ohlcv(symbol, timeframe=input_tf, limit=limit)
df = pd.DataFrame(bars[:], columns=['timestamp',
'open', 'high', 'low', 'close', 'volume'])
df['dt'] = pd.to_datetime(df['timestamp'], unit='ms')
df.set_index('dt', inplace=True)
df.index = df.index.tz_localize('UTC').tz_convert('Asia/Shanghai')
return df
def isKdj(last, last_pre):
# 判断是否是金叉
if (float(last_pre['macd']) < 0) and (float(last['macd']) > 0):
return True
return False
def isDeadFork(last, last_pre):
# 判断是否是死叉
if (float(last_pre['macd']) > 0) and (float(last['macd']) < 0):
return True
return False
def getMACD(df, lenght=-60):
if len(df['close'].values) < 100:
return False, None
close_p = df['close'].values
df['dif'], df['dea'], df['macd'] = talib.MACD(close_p,
fastperiod=12,
slowperiod=26,
signalperiod=9)
return df[lenght:]
def getTarget(df):
close = df['close'].values
df['ema'] = talib.EMA(np.array(close), timeperiod=10)
df['ema_200'] = talib.EMA(np.array(close), timeperiod=200)
df['ma'] = talib.MA(close, timeperiod=10)
df['rsi'] = talib.RSI(close, timeperiod=14)
return df
# 多头信号
def isBuyCrondSignal(last):
if last['ema'] > last['ma'] and (last['rsi'] > 50 and last['rsi'] < 70) and last['low'] >= last['ma'] and last['close'] > last['open']:
return True
return False
def isBuyFristSignal(data):
data = data.sort_values(by=['timestamp'], ascending=False)
# print(data)
data_len = len(data)
signal_num = 0
first_data = data.iloc[1]
# print(1, first_data['close'], first_data['ema'])
is_buy_signal = isBuyCrondSignal(first_data)
for x in range(2, data_len):
tmp = data.iloc[x]
# print(data.iloc[x])
# print(x, tmp['close'], tmp['ema'])
if isBuyCrondSignal(tmp):
signal_num = + 1
# print('signal_num:', signal_num)
if (tmp['ema'] < tmp['ma']):
break
if str(tmp['ema']) == 'nan':
break
print("is_buy_signal:", is_buy_signal, 'signal_num:', signal_num)
if is_buy_signal and signal_num == 0:
return True
return False
# 空头信号
def isSellCrondSignal(last):
if last['ema'] < last['ma'] and (last['rsi'] > 30 and last['rsi'] < 50) and last['high'] <= last['ema'] and last['close'] < last['open']:
return True
return False
def isSellFristSignal(data):
data = data.sort_values(by=['timestamp'], ascending=False)
# print(data)
data_len = len(data)
signal_num = 0
first_data = data.iloc[1]
# print(1, first_data['close'], first_data['ema'])
is_sell_signal = isSellCrondSignal(first_data)
for x in range(2, data_len):
tmp = data.iloc[x]
# print(data.iloc[x])
# print(x, tmp['close'], tmp['ema'])
if isSellCrondSignal(tmp):
signal_num = + 1
# print('signal_num:', signal_num)
if (tmp['ema'] < tmp['ma']):
break
if str(tmp['ema']) == 'nan':
break
print("is_sell_signal:", is_sell_signal, 'signal_num:', signal_num)
if is_sell_signal and signal_num == 0:
return True
return False
def monentunTrade(data, tag, timeframe):
data = getTarget(data)
# print(data)
key_data = data.tail(3)
print(key_data)
last_pre = key_data.iloc[0]
last = key_data.iloc[1]
obj = common.MsgTpl()
symbol = tag.upper() + '/USDT'
obj.setName(symbol)
obj.setStrategyName("动量交易策略")
obj.setTimeFrame(timeframe)
obj.setOpenTime(last['timestamp'] / 1000)
# 买入信号,并且收盘价要大于200 ema
if isBuyFristSignal(data) and last['close'] > last['ema_200']:
obj.setStrategicDt('buy')
# 做多止损点
stop_loss_price = last['ma']
stop_loss_price = common.roundVal(stop_loss_price, last['open'])
buy_status, open_price, closing_price = onBuyOrder(
symbol, stop_loss_price, 0.005, timeframe)
if buy_status:
# 做多止损点
obj.setStopLossPrice(str(stop_loss_price))
obj.setOpenPrice(str(open_price))
obj.setClosingPrice(str(closing_price))
obj.setContent("动量交易策略做多!")
msg = obj.toText()
print(msg)
common.notifyMsg(msg, timeframe, tag)
common.writeLog(msg)
# 卖出信号,并且收盘价要小于200 ema
# if isSellFristSignal(data) and last['close'] < last['ema_200']:
# obj.setStrategicDt('sell')
# stop_loss_price = last['ma']
# stop_loss_price = common.roundVal(stop_loss_price, last['open'])
# sell_status, open_price, closing_price = onSellOrder(
# symbol, stop_loss_price, 0.005, timeframe)
# if sell_status:
# obj.setStopLossPrice(str(stop_loss_price))
# obj.setOpenPrice(str(open_price))
# obj.setClosingPrice(str(closing_price))
# obj.setStrategicDt('sell')
# obj.setContent("动量交易策略作空!")
# msg = obj.toText()
# print(msg)
# common.notifyMsg(msg, timeframe, tag)
# common.writeLog(msg)
def mainProcess(tag, timeframe='15m'):
symbol = tag.upper() + '/USDT'
data = getOnlineData(symbol, timeframe)
monentunTrade(data, tag, timeframe)
def foreachList():
tag_list = ['btc', 'xrp']
for tag in tag_list:
mainProcess(tag, '15m')
time.sleep(1)
def longRun():
while True:
foreachList()
time.sleep(1)
def debug():
while True:
mainProcess('btc', '5m')
time.sleep(1)
if __name__ == "__main__":
func = sys.argv[1]
if func == 'long':
longRun()
elif func == 'run':
debug()
else:
print('error')
@@ -0,0 +1,48 @@
# cd /www/server/mdserver-web && source bin/activate
# python3 plugins/cryptocurrency_trade/ccxt/strategy/notify_demo.py run
# python3 plugins/cryptocurrency_trade/ccxt/strategy/notify_demo.py long
import ccxt
import talib
import pandas as pd
import time
import sys
import os
from pprint import pprint
sys.path.append(os.getcwd() + "/plugins/cryptocurrency_trade/strategy")
import common
sys.path.append(os.getcwd() + "/class/core")
import mw
def run():
print('debug')
def longRun():
while True:
obj = common.MsgTpl()
obj.setName("通知测试")
obj.setStrategyName("无")
obj.setTimeFrame("1m")
obj.setContent("60s通知测试")
msg = obj.toText()
print(msg)
common.notifyMsg(msg, '1m', 'debug')
common.writeLog(msg)
time.sleep(3)
if __name__ == "__main__":
func = sys.argv[1]
if func == 'run':
run()
if func == 'long':
longRun()
else:
print('error')
@@ -0,0 +1,294 @@
# cd /www/server/mdserver-web && source bin/activate
# python3 plugins/cryptocurrency_trade/ccxt/strategy/on_g_test.py t_buy_open
# python3 plugins/cryptocurrency_trade/ccxt/strategy/on_g_test.py t_buy_close
# python3 plugins/cryptocurrency_trade/ccxt/strategy/on_g_test.py t_sell_open
# python3 plugins/cryptocurrency_trade/ccxt/strategy/on_g_test.py t_sell_cloe
# 获取仓位数据
# python3 plugins/cryptocurrency_trade/ccxt/strategy/on_g_test.py t_get_trade
# API地址
# https://www.gate.io/docs/developers/apiv4/zh_CN/#api
import ccxt
import talib
import sys
import os
import time
import pandas as pd
# import pandas_ta as ta
from pprint import pprint
import numpy as np
sys.path.append(os.getcwd() + "/plugins/cryptocurrency_trade/strategy")
import common
sys.path.append(os.getcwd() + "/class/core")
import mw
exchange = ccxt.gate({
"apiKey": '756e1ff80526cb0ac9620c75680fc506',
"secret": '95ac89362056bcf12ce37aabff6eb7ec78185483105f39b4a35e8dc8db8b4d3c',
})
exchange.load_markets()
def t_get_trade():
data = exchange.fetchPositions()
print(data)
def btc_test():
closing_price = 24599.9
stop_loss_price = 24740.4
# ---------------------------
stop_loss_args = {
'ccy': "USDT",
'reduceOnly': True,
'tdMode': "cross",
'slOrdPx': "-1",
'slTriggerPx': stop_loss_price,
}
print('---------止损价 执行 START ----------------------------------')
sl_amount = stop_loss_price * 0.001
print(amount)
data = exchange.create_order(
'BTC/USDT', 'limit', 'buy', sl_amount, stop_loss_price, stop_loss_args)
print(data)
print('---------止损价 执行 END ----------------------------------')
print('---------止盈价 执行 START ----------------------------------')
closing_price_args = {
'ccy': "USDT",
'reduceOnly': True,
'tdMode': "cross",
'tpOrdPx': "-1",
'tpTriggerPx': closing_price,
}
cp_amount = closing_price * 0.001
print(amount)
data = exchange.create_order(
'BTC/USDT', 'limit', 'buy', cp_amount, closing_price, closing_price_args)
print(data)
print('---------止盈价 执行 END ----------------------------------')
def testK_buy_open_sz():
# 做多开仓
data = exchange.fetchTicker('BTC/USDT')
print(data)
# data = exchange.createMarketBuyOrder('DOT/USDT', 1, {"tdMode": "cross"})
# print(data)
# print(type(data))
def testK_buy_open():
# 做多开仓
# print(dir(exchange))
# exchange['options']['createMarketBuyOrderRequiresPrice'] = False
data = exchange.fetch_ticker('BTC/USDT')
print("now price:", data['ask'])
amount = 0.001
price = data['ask']
cost = amount * float(price)
print('total price:', cost)
print('amount price:', amount)
# a_amount = round(amount / data['ask'], 5)
# print('amount :', amount)
# print('amount :', str(amount))
#
data = exchange.createOrder(
"BTC/USDT", type="limit", side="buy", amount=amount, price=price, params={'account': "cross_margin"})
# data = exchange.createMarketBuyOrder('BTC/USDT', amount)
print(data)
print(type(data))
# 数据
# {'info': {'clOrdId': 'e847386590ce4dBC58e8b0afb0fe70cc', 'ordId': '554437054223302656', 'sCode': '0', 'sMsg': 'Order placed', 'tag': 'e847386590ce4dBC'}, 'id': '554437054223302656', 'clientOrderId': 'e847386590ce4dBC58e8b0afb0fe70cc', 'timestamp': None, 'datetime': None, 'lastTradeTimestamp': None, 'symbol': 'DOT/USDT', 'type': 'market', 'timeInForce': None, 'postOnly': None, 'side': 'buy', 'price': None, 'stopPrice': None, 'triggerPrice': None, 'average': None, 'cost': None, 'amount': None, 'filled': None, 'remaining': None, 'status': None, 'fee': None, 'trades': [], 'reduceOnly': None, 'fees': []}
# 查询委托单
# order_id = data['info']['ordId']
# order_id = '554437054223302656'
# data = exchange.fetchOrder(order_id, 'BTC/USDT')
# print(data['info'])
# {'info': {'accFillSz': '0.190548', 'algoClOrdId': '', 'algoId': '', 'avgPx': '5.248', 'cTime': '1678441709955', 'cancelSource': '', 'cancelSourceReason': '', 'category': 'normal', 'ccy': 'USDT', 'clOrdId': 'e847386590ce4dBCeaddfd1494dc7080', 'fee': '-0.000190548', 'feeCcy': 'DOT', 'fillPx': '5.248', 'fillSz': '0.190548', 'fillTime': '1678441709957', 'instId': 'DOT-USDT', 'instType': 'MARGIN', 'lever': '10', 'ordId': '554359943143833600', 'ordType': 'market', 'pnl': '0', 'posSide': 'net', 'px': '', 'quickMgnType': '', 'rebate': '0', 'rebateCcy': 'USDT', 'reduceOnly': 'false', 'side': 'buy', 'slOrdPx': '', 'slTriggerPx': '', 'slTriggerPxType': '', 'source': '', 'state': 'filled', 'sz': '1', 'tag': 'e847386590ce4dBC', 'tdMode': 'cross', 'tgtCcy': '', 'tpOrdPx': '', 'tpTriggerPx': '', 'tpTriggerPxType': '', 'tradeId': '81184616', 'uTime': '1678441709960'}, 'id': '554359943143833600', 'clientOrderId': 'e847386590ce4dBCeaddfd1494dc7080', 'timestamp': 1678441709955, 'datetime': '2023-03-10T09:48:29.955Z', 'lastTradeTimestamp': 1678441709957, 'symbol': 'DOT/USDT', 'type': 'market', 'timeInForce': 'IOC', 'postOnly': None, 'side': 'buy', 'price': 5.248, 'stopPrice': None, 'triggerPrice': None, 'average': 5.248, 'cost': 0.999995904, 'amount': 1.0, 'filled': 0.190548, 'remaining': 0.809452, 'status': 'closed', 'fee': {'cost': 0.000190548, 'currency': 'DOT'}, 'trades': [], 'reduceOnly': False, 'fees': [{'cost': 0.000190548, 'currency': 'DOT'}]}
# open_price = data['info']['avgPx']
# print("开仓平均价", open_price)
# # 止盈价
# closing_price = float(open_price) * float((1 + 0.005))
# closing_price = common.roundVal(closing_price, open_price)
# print("止盈价", closing_price)
# # 止损价
# stop_loss_price = float(open_price) * float((1 - 0.01))
# stop_loss_price = common.roundVal(stop_loss_price, open_price)
# print("止损价", stop_loss_price)
# property_val = float(data['info']['accFillSz']) + \
# float(data['info']['fee'])
# # 相同位数
# property_val = common.roundValCeil(property_val, data['info']['accFillSz'])
# print("可平仓资产", property_val)
# closed_orders = exchange.fetchClosedOrders('DOT/USDT', limit=2)
# print('closed_orders', closed_orders)
# print(exchange.fetchBalance())
# 可以用,限价单
# time.sleep(1)
# data = exchange.createLimitSellOrder(
# 'DOT/USDT', property_val, closing_price, {"tdMode": "cross", 'ccy': 'USDT', "reduceOnly": True})
# print(data)
# print(type(data))
# 止损价
# 止盈价
# exchange_params = {
# 'ccy': "USDT",
# 'reduceOnly': True,
# 'tdMode': "cross",
# 'tpOrdPx': "-1",
# 'tpTriggerPx': closing_price,
# 'slOrdPx': "-1",
# 'slTriggerPx': stop_loss_price,
# }
# print('---------止损价 执行----------------------------------')
# data = exchange.create_order(
# 'BTC/USDT', 'limit', 'sell', property_val, closing_price, exchange_params)
# print(data)
# print(type(data))
# print('---------止盈价 执行----------------------------------')
# exchange_params = {
# 'stopPrice': closing_price,
# 'type': 'stopLimit',
# }
# data = exchange.create_order(
# 'DOT/USDT', 'limit', 'sell', property_val, closing_price, exchange_params)
# print(data)
# print(type(data))
def testK_buy_close():
# 平多
data = exchange.create_limit_buy_order(
'DOT/USDT', 1, 5, {"tdMode": "cross"})
print(data)
print(type(data))
# closed_orders = exchange.fetchClosedOrders('BTC/USDT', limit=2)
# print(closed_orders)
# closed_orders = exchange.fetchMyTrades('ETH/USDT', limit=2)
# print(closed_orders)
def testK_sell_open():
# 做空开仓
# data = exchange.createMarketSellOrder(
# 'DOT/USDT', 1, {"tdMode": "cross", 'ccy': "USDT", })
# print(data)
# print(type(data))
# 数据
# {'info': {'clOrdId': 'e847386590ce4dBC58e8b0afb0fe70cc', 'ordId': '554437054223302656', 'sCode': '0', 'sMsg': 'Order placed', 'tag': 'e847386590ce4dBC'}, 'id': '554437054223302656', 'clientOrderId': 'e847386590ce4dBC58e8b0afb0fe70cc', 'timestamp': None, 'datetime': None, 'lastTradeTimestamp': None, 'symbol': 'DOT/USDT', 'type': 'market', 'timeInForce': None, 'postOnly': None, 'side': 'buy', 'price': None, 'stopPrice': None, 'triggerPrice': None, 'average': None, 'cost': None, 'amount': None, 'filled': None, 'remaining': None, 'status': None, 'fee': None, 'trades': [], 'reduceOnly': None, 'fees': []}
# # 查询委托单
# order_id = data['info']['ordId']
order_id = '554516809819832320'
data = exchange.fetchOrder(order_id, 'DOT/USDT')
print(data['info'])
# {'info': {'accFillSz': '0.190548', 'algoClOrdId': '', 'algoId': '', 'avgPx': '5.248', 'cTime': '1678441709955', 'cancelSource': '', 'cancelSourceReason': '', 'category': 'normal', 'ccy': 'USDT', 'clOrdId': 'e847386590ce4dBCeaddfd1494dc7080', 'fee': '-0.000190548', 'feeCcy': 'DOT', 'fillPx': '5.248', 'fillSz': '0.190548', 'fillTime': '1678441709957', 'instId': 'DOT-USDT', 'instType': 'MARGIN', 'lever': '10', 'ordId': '554359943143833600', 'ordType': 'market', 'pnl': '0', 'posSide': 'net', 'px': '', 'quickMgnType': '', 'rebate': '0', 'rebateCcy': 'USDT', 'reduceOnly': 'false', 'side': 'buy', 'slOrdPx': '', 'slTriggerPx': '', 'slTriggerPxType': '', 'source': '', 'state': 'filled', 'sz': '1', 'tag': 'e847386590ce4dBC', 'tdMode': 'cross', 'tgtCcy': '', 'tpOrdPx': '', 'tpTriggerPx': '', 'tpTriggerPxType': '', 'tradeId': '81184616', 'uTime': '1678441709960'}, 'id': '554359943143833600', 'clientOrderId': 'e847386590ce4dBCeaddfd1494dc7080', 'timestamp': 1678441709955, 'datetime': '2023-03-10T09:48:29.955Z', 'lastTradeTimestamp': 1678441709957, 'symbol': 'DOT/USDT', 'type': 'market', 'timeInForce': 'IOC', 'postOnly': None, 'side': 'buy', 'price': 5.248, 'stopPrice': None, 'triggerPrice': None, 'average': 5.248, 'cost': 0.999995904, 'amount': 1.0, 'filled': 0.190548, 'remaining': 0.809452, 'status': 'closed', 'fee': {'cost': 0.000190548, 'currency': 'DOT'}, 'trades': [], 'reduceOnly': False, 'fees': [{'cost': 0.000190548, 'currency': 'DOT'}]}
open_price = data['info']['avgPx']
print("开仓平均价", open_price)
# 止盈价
closing_price = float(open_price) * float((1 - 0.005))
closing_price = common.roundVal(closing_price, open_price)
print("止盈价", closing_price)
# 止损价
stop_loss_price = float(open_price) * float((1 + 0.01))
stop_loss_price = common.roundVal(stop_loss_price, open_price)
print("止损价", stop_loss_price)
property_val = float(data['info']['accFillSz'])
# 相同位数
print("可平仓资产", property_val)
# 止损价
# 止盈价
exchange_params = {
'ccy': "USDT",
'reduceOnly': True,
'tdMode': "cross",
'tpOrdPx': "-1",
'tpTriggerPx': closing_price,
'slOrdPx': "-1",
'slTriggerPx': stop_loss_price,
}
print('---------止损价 执行----------------------------------')
data = exchange.create_order(
'DOT/USDT', 'limit', 'buy', property_val, closing_price, exchange_params)
print(data)
print(type(data))
def testK_sell_close():
# 平多
data = exchange.create_limit_buy_order(
'DOT/USDT', 1, 5, {"tdMode": "cross"})
print(data)
print(type(data))
# closed_orders = exchange.fetchClosedOrders('BTC/USDT', limit=2)
# print(closed_orders)
# closed_orders = exchange.fetchMyTrades('ETH/USDT', limit=2)
# print(closed_orders)
if __name__ == "__main__":
func = sys.argv[1]
if func == 'long':
longRun()
elif func == 'run':
debug()
elif func == 'test':
testKdan()
elif func == 't_get_trade':
t_get_trade()
elif func == 't_buy_open':
testK_buy_open()
elif func == 't_buy_close':
testK_buy_close()
elif func == 't_sell_open':
testK_sell_open()
elif func == 't_sell_cloe':
testK_sell_close()
else:
print('error')
@@ -0,0 +1,437 @@
# cd /www/server/mdserver-web && source bin/activate
# python3 plugins/cryptocurrency_trade/ccxt/strategy/online_macd_trade.py run
# python3 plugins/cryptocurrency_trade/ccxt/strategy/online_macd_trade.py long
import ccxt
import talib
import sys
import os
import time
import json
import pandas as pd
# import pandas_ta as ta
from pprint import pprint
import numpy as np
sys.path.append(os.getcwd() + "/plugins/cryptocurrency_trade/strategy")
import common
sys.path.append(os.getcwd() + "/class/core")
import mw
exchange = common.initEx()
exchange.load_markets()
# 默认开仓数据
# default_open_num = 10
default_open = {
'ETH/USDT': 30,
'DOT/USDT': 30,
'CEL/USDT': 30,
}
default_sell = {
'ETH/USDT': 0.02,
'DOT/USDT': 5,
'CEL/USDT': 85,
}
# 做多开仓
def onBuyOrderTry(symbol, stop_loss_price, profit=0.005, timeframe='15m'):
# 信号只在一个周期内执行一次|start
lock_file = common.getServerDir() + '/signal.json'
if not os.path.exists(lock_file):
mw.writeFile(lock_file, '{}')
stype = symbol.replace('/', '_') + '_' + timeframe
trigger_time = common.toUnixTimeSecond(timeframe)
lock_data = json.loads(mw.readFile(lock_file))
if stype in lock_data:
diff_time = time.time() - lock_data[stype]['do_time']
if diff_time >= trigger_time:
lock_data[stype]['do_time'] = time.time()
else:
return False, 0, 0
else:
lock_data[stype] = {'do_time': time.time()}
mw.writeFile(lock_file, json.dumps(lock_data))
# 信号只在一个周期内执行一次|end
common.writeLogEx('------做多----------------------------------', symbol)
default_open_num = default_open[symbol]
# 做多开仓 | 市价
data = exchange.createMarketBuyOrder(
symbol, default_open_num, {"tdMode": "cross"})
common.writeLogEx('开仓数据:', symbol)
common.writeLogEx(json.dumps(data), symbol)
order_id = data['info']['ordId']
order_data = exchange.fetchOrder(order_id, symbol)
common.writeLogEx('订单数据:', symbol)
common.writeLogEx(json.dumps(order_data), symbol)
# 实际开场平均价
open_price = order_data['info']['avgPx']
# 做多-止损价大于开仓价,重设止损价
if float(stop_loss_price) <= float(open_price):
stop_loss_price = float(open_price) * float((1 - 0.003))
# property_val = float(order_data['info']['accFillSz']) + float(order_data['info']['fee'])
property_val = common.addition(
order_data['info']['accFillSz'], order_data['info']['fee'])
property_val = float(property_val)
# 可平仓的数量
property_val = common.roundValCeil(
property_val, order_data['info']['accFillSz'])
common.writeLogEx('可平仓资产:' + str(property_val), symbol)
# 止盈价
diff = float(open_price) - float(stop_loss_price)
closing_price_c = float(open_price) + (diff * 2)
closing_price = float(open_price) * float((1 + profit))
# 选择盈利多的
if closing_price_c > closing_price:
closing_price = closing_price_c
closing_price = common.roundVal(closing_price, stop_loss_price)
# stop_loss_price = common.roundVal(stop_loss_price, open_price)
common.writeLogEx('实际开仓价:' + str(open_price), symbol)
common.writeLogEx('止盈价:' + str(closing_price), symbol)
common.writeLogEx('止损价:' + str(stop_loss_price), symbol)
# 设置 - 止损价/止盈价
sl_exchange_params = {
'ccy': "USDT",
'reduceOnly': True,
'tdMode': "cross",
'slOrdPx': "-1",
'slTriggerPx': stop_loss_price,
}
# 止损条件单
common.writeLogEx('止损参数:' + json.dumps([symbol, 'limit', 'sell',
property_val, stop_loss_price, sl_exchange_params]), symbol)
sl_cond_data = exchange.create_order(
symbol, 'limit', 'sell', property_val, stop_loss_price, sl_exchange_params)
common.writeLogEx('止损价数据:', symbol)
common.writeLogEx(json.dumps(sl_cond_data), symbol)
# 止赢条件单
tp_exchange_params = {
'ccy': "USDT",
'reduceOnly': True,
'tdMode': "cross",
'tpOrdPx': "-1",
'tpTriggerPx': closing_price,
}
common.writeLogEx('止盈参数:' + json.dumps([symbol, 'limit', 'sell',
property_val, closing_price, tp_exchange_params]), symbol)
tp_cond_data = exchange.create_order(
symbol, 'limit', 'sell', property_val, closing_price, tp_exchange_params)
common.writeLogEx('止赢数据:', symbol)
common.writeLogEx(json.dumps(tp_cond_data), symbol)
common.writeLogEx('------做多 end----------------------------------', symbol)
return True, open_price, closing_price
def onBuyOrder(symbol, stop_loss_price, profit=0.005, timeframe='15m'):
# 做多开仓
# profit 百分比
try:
return onBuyOrderTry(symbol, stop_loss_price, profit, timeframe)
except Exception as e:
common.writeLogErrorEx(mw.getTracebackInfo(), symbol)
return False, 0, 0
def onSellOrderTry(symbol, stop_loss_price, profit=0.005, timeframe='15m'):
# 信号只在一个周期内执行一次|start
lock_file = common.getServerDir() + '/signal.json'
if not os.path.exists(lock_file):
mw.writeFile(lock_file, '{}')
stype = symbol.replace('/', '_') + '_' + timeframe
trigger_time = common.toUnixTimeSecond(timeframe)
lock_data = json.loads(mw.readFile(lock_file))
if stype in lock_data:
diff_time = time.time() - lock_data[stype]['do_time']
if diff_time >= trigger_time:
lock_data[stype]['do_time'] = time.time()
else:
return False, 0, 0
else:
lock_data[stype] = {'do_time': time.time()}
mw.writeFile(lock_file, json.dumps(lock_data))
# 信号只在一个周期内执行一次|end
common.writeLogEx('------做空----------------------------------', symbol)
# 计算借币卖币多多少,以USDT为基准
# sell_num = float(default_open_num) / float(stop_loss_price)
# sell_num = round(sell_num, 8)
sell_num = default_sell[symbol]
# 做空开仓 | 市价
data = exchange.createMarketSellOrder(
symbol, sell_num, {"tdMode": "cross", 'ccy': "USDT"})
common.writeLogEx('开仓数据:', symbol)
common.writeLogEx(json.dumps(data), symbol)
order_id = data['info']['ordId']
order_data = exchange.fetchOrder(order_id, symbol)
common.writeLogEx('订单数据:', symbol)
common.writeLogEx(json.dumps(order_data), symbol)
# 实际开场平均价
open_price = order_data['info']['avgPx']
common.writeLogEx('可平仓资产:' + str(sell_num), symbol)
# 做空-止损价小于开仓价,重设止损价
if float(stop_loss_price) <= float(open_price):
stop_loss_price = float(open_price) * float((1 + 0.003))
# 止盈价
diff = float(stop_loss_price) - float(open_price)
closing_price_c = float(open_price) - (diff * 2)
closing_price = float(open_price) * float((1 - profit))
# 选择盈利多的
if closing_price_c < closing_price:
closing_price = closing_price_c
closing_price = common.roundVal(closing_price, open_price)
stop_loss_price = common.roundVal(stop_loss_price, open_price)
common.writeLogEx('实际开仓价:' + str(open_price), symbol)
common.writeLogEx('止盈价:' + str(closing_price), symbol)
common.writeLogEx('止损价:' + str(stop_loss_price), symbol)
# 设置 - 止损价
sl_exchange_params = {
'ccy': "USDT",
'reduceOnly': True,
'tdMode': "cross",
'slOrdPx': "-1",
'slTriggerPx': stop_loss_price,
}
sl_amount = common.multiply(stop_loss_price, sell_num)
# 解决平仓时,未全部平仓
sl_amount = common.addition(sl_amount, 0.1)
common.writeLogEx('止损总价值:' + str(sl_amount), symbol)
common.writeLogEx('止损参数:' + json.dumps([symbol, 'limit', 'buy', float(
sl_amount), stop_loss_price, sl_exchange_params]), symbol)
sl_cond_data = exchange.create_order(
symbol, 'limit', 'buy', sl_amount, stop_loss_price, sl_exchange_params)
common.writeLogEx('止损价数据:', symbol)
common.writeLogEx(json.dumps(sl_cond_data), symbol)
tp_exchange_params = {
'ccy': "USDT",
'reduceOnly': True,
'tdMode': "cross",
'tpOrdPx': "-1",
'tpTriggerPx': closing_price,
}
# 设置 -止盈价
tp_amount = common.multiply(closing_price, sell_num)
# 解决平仓时,未全部平仓
tp_amount = common.addition(tp_amount, 0.1)
common.writeLogEx('止盈总价值:' + str(tp_amount), symbol)
common.writeLogEx('止盈参数:' + json.dumps([symbol, 'limit', 'buy', float(
tp_amount), closing_price, tp_exchange_params]), symbol)
tp_cond_data = exchange.create_order(
symbol, 'limit', 'buy', tp_amount, closing_price, tp_exchange_params)
common.writeLogEx('止盈价数据:', symbol)
common.writeLogEx(json.dumps(tp_cond_data), symbol)
common.writeLogEx('------做空 end----------------------------------', symbol)
return True, open_price, closing_price
def onSellOrder(symbol, stop_loss_price, profit=0.005, timeframe='15m'):
# 做空开仓
# profit 百分比
try:
return onSellOrderTry(symbol, stop_loss_price, profit, timeframe)
except Exception as e:
common.writeLogErrorEx(mw.getTracebackInfo(), symbol)
return False, 0, 0
def getOnlineData(symbol, input_tf="15m", limit=230):
bars = exchange.fetch_ohlcv(symbol, timeframe=input_tf, limit=limit)
df = pd.DataFrame(bars[:], columns=['timestamp',
'open', 'high', 'low', 'close', 'volume'])
df['dt'] = pd.to_datetime(df['timestamp'], unit='ms')
df.set_index('dt', inplace=True)
df.index = df.index.tz_localize('UTC').tz_convert('Asia/Shanghai')
return df
def isKdj(last, last_pre):
# 判断是否是金叉
if (float(last_pre['macd']) < 0) and (float(last['macd']) > 0):
return True
return False
def isDeadFork(last, last_pre):
# 判断是否是死叉
if (float(last_pre['macd']) > 0) and (float(last['macd']) < 0):
return True
return False
def getMACD(df, lenght=-60):
if len(df['close'].values) < 100:
return False, None
close_p = df['close'].values
df['dif'], df['dea'], df['macd'] = talib.MACD(close_p,
fastperiod=12,
slowperiod=26,
signalperiod=9)
return df[lenght:]
def getEMA(df):
close_p = df['close'].values
df['ema'] = talib.EMA(np.array(close_p), timeperiod=200)
return df
def doneMacd(data, tag, timeframe):
data = getEMA(data)
ma_data = getMACD(data)
# alen = len(data)
# print(ma_data)
t_data = ma_data.tail(3)
# print(t_data)
last_pre = t_data.iloc[0]
last = t_data.iloc[1]
# print(last)
# print(last.index)
# print('close:', last['close'], 'ema:', last['ema'])
obj = common.MsgTpl()
symbol = tag.upper() + '/USDT'
obj.setName(symbol)
obj.setStrategyName("MACD检查")
obj.setTimeFrame(timeframe)
obj.setOpenTime(last['timestamp'] / 1000)
now_data = t_data.iloc[2]
# print('now_data:', now_data)
# msg = obj.toText()
# print(msg)
if isKdj(last, last_pre) and last['close'] > last['ema']:
# if isKdj(last, last_pre):
# closing_price = common.calc_ClosingPrice(
# now_data['close'], last_pre['low'], 'buy')
# # print('closing_price:', closing_price)
# 做多止损点
stop_loss_price = last_pre['low']
buy_status, open_price, closing_price = onBuyOrder(
symbol, stop_loss_price, 0.005, timeframe)
if buy_status:
obj.setStrategicDt('buy')
# 做多止损点
obj.setStopLossPrice(str(stop_loss_price))
obj.setOpenPrice(str(open_price))
obj.setClosingPrice(str(closing_price))
obj.setContent("检查到金叉状态")
msg = obj.toText()
print(msg)
common.notifyMsg(msg, timeframe, tag)
common.writeLog(msg)
if isDeadFork(last, last_pre) and last['close'] < last['ema']:
# if isDeadFork(last, last_pre):
# closing_price = common.calc_ClosingPrice(
# now_data['close'], last_pre['high'], 'sell')
# 做空止损点
stop_loss_price = last_pre['high']
sell_status, open_price, closing_price = onSellOrder(
symbol, stop_loss_price, 0.005, timeframe)
if sell_status:
obj.setStopLossPrice(str(stop_loss_price))
obj.setOpenPrice(str(open_price))
obj.setClosingPrice(str(closing_price))
obj.setStrategicDt('sell')
obj.setContent("检查到死叉状态")
msg = obj.toText()
print(msg)
common.notifyMsg(msg, timeframe, tag)
common.writeLog(msg)
def mainProcess(tag, timeframe='15m'):
symbol = tag.upper() + '/USDT'
data = getOnlineData(symbol, timeframe)
doneMacd(data, tag, timeframe)
def foreachList():
tag_list = [
'eth', 'dot'
]
for tag in tag_list:
mainProcess(tag, '15m')
time.sleep(1)
def longRun():
while True:
foreachList()
time.sleep(3)
def debug():
while True:
mainProcess('xrp', '1m')
time.sleep(3)
if __name__ == "__main__":
func = sys.argv[1]
if func == 'long':
longRun()
elif func == 'run':
debug()
else:
print('error')
@@ -0,0 +1,273 @@
# cd /www/server/mdserver-web && source bin/activate
# python3 plugins/cryptocurrency_trade/ccxt/strategy/online_test.py t_buy_open
# python3 plugins/cryptocurrency_trade/ccxt/strategy/online_test.py t_buy_close
# python3 plugins/cryptocurrency_trade/ccxt/strategy/online_test.py t_sell_open
# python3 plugins/cryptocurrency_trade/ccxt/strategy/online_test.py t_sell_cloe
# 获取仓位数据
# python3 plugins/cryptocurrency_trade/ccxt/strategy/online_test.py t_get_trade
import ccxt
import talib
import sys
import os
import time
import pandas as pd
# import pandas_ta as ta
from pprint import pprint
import numpy as np
sys.path.append(os.getcwd() + "/plugins/cryptocurrency_trade/strategy")
import common
sys.path.append(os.getcwd() + "/class/core")
import mw
exchange = common.initEx()
exchange.load_markets()
def t_get_trade():
data = exchange.fetchPositions()
print(data)
def btc_test():
closing_price = 24599.9
stop_loss_price = 24740.4
# ---------------------------
stop_loss_args = {
'ccy': "USDT",
'reduceOnly': True,
'tdMode': "cross",
'slOrdPx': "-1",
'slTriggerPx': stop_loss_price,
}
print('---------止损价 执行 START ----------------------------------')
sl_amount = stop_loss_price * 0.003
print(amount)
data = exchange.create_order(
'BTC/USDT', 'limit', 'buy', sl_amount, stop_loss_price, stop_loss_args)
print(data)
print('---------止损价 执行 END ----------------------------------')
print('---------止盈价 执行 START ----------------------------------')
closing_price_args = {
'ccy': "USDT",
'reduceOnly': True,
'tdMode': "cross",
'tpOrdPx': "-1",
'tpTriggerPx': closing_price,
}
cp_amount = closing_price * 0.003
print(amount)
data = exchange.create_order(
'BTC/USDT', 'limit', 'buy', cp_amount, closing_price, closing_price_args)
print(data)
print('---------止盈价 执行 END ----------------------------------')
def testK_buy_open_sz():
# 做多开仓
data = exchange.fetchTicker('DOT/USDT')
print(data)
# data = exchange.createMarketBuyOrder('DOT/USDT', 1, {"tdMode": "cross"})
# print(data)
# print(type(data))
def testK_buy_open():
# 做多开仓
data = exchange.createMarketBuyOrder(
'DOT/USDT', 1, {"tdMode": "cross"})
print(data)
print(type(data))
# 数据
# {'info': {'clOrdId': 'e847386590ce4dBC58e8b0afb0fe70cc', 'ordId': '554437054223302656', 'sCode': '0', 'sMsg': 'Order placed', 'tag': 'e847386590ce4dBC'}, 'id': '554437054223302656', 'clientOrderId': 'e847386590ce4dBC58e8b0afb0fe70cc', 'timestamp': None, 'datetime': None, 'lastTradeTimestamp': None, 'symbol': 'DOT/USDT', 'type': 'market', 'timeInForce': None, 'postOnly': None, 'side': 'buy', 'price': None, 'stopPrice': None, 'triggerPrice': None, 'average': None, 'cost': None, 'amount': None, 'filled': None, 'remaining': None, 'status': None, 'fee': None, 'trades': [], 'reduceOnly': None, 'fees': []}
# 查询委托单
order_id = data['info']['ordId']
# order_id = '554437054223302656'
data = exchange.fetchOrder(order_id, 'DOT/USDT')
print(data['info'])
# {'info': {'accFillSz': '0.190548', 'algoClOrdId': '', 'algoId': '', 'avgPx': '5.248', 'cTime': '1678441709955', 'cancelSource': '', 'cancelSourceReason': '', 'category': 'normal', 'ccy': 'USDT', 'clOrdId': 'e847386590ce4dBCeaddfd1494dc7080', 'fee': '-0.000190548', 'feeCcy': 'DOT', 'fillPx': '5.248', 'fillSz': '0.190548', 'fillTime': '1678441709957', 'instId': 'DOT-USDT', 'instType': 'MARGIN', 'lever': '10', 'ordId': '554359943143833600', 'ordType': 'market', 'pnl': '0', 'posSide': 'net', 'px': '', 'quickMgnType': '', 'rebate': '0', 'rebateCcy': 'USDT', 'reduceOnly': 'false', 'side': 'buy', 'slOrdPx': '', 'slTriggerPx': '', 'slTriggerPxType': '', 'source': '', 'state': 'filled', 'sz': '1', 'tag': 'e847386590ce4dBC', 'tdMode': 'cross', 'tgtCcy': '', 'tpOrdPx': '', 'tpTriggerPx': '', 'tpTriggerPxType': '', 'tradeId': '81184616', 'uTime': '1678441709960'}, 'id': '554359943143833600', 'clientOrderId': 'e847386590ce4dBCeaddfd1494dc7080', 'timestamp': 1678441709955, 'datetime': '2023-03-10T09:48:29.955Z', 'lastTradeTimestamp': 1678441709957, 'symbol': 'DOT/USDT', 'type': 'market', 'timeInForce': 'IOC', 'postOnly': None, 'side': 'buy', 'price': 5.248, 'stopPrice': None, 'triggerPrice': None, 'average': 5.248, 'cost': 0.999995904, 'amount': 1.0, 'filled': 0.190548, 'remaining': 0.809452, 'status': 'closed', 'fee': {'cost': 0.000190548, 'currency': 'DOT'}, 'trades': [], 'reduceOnly': False, 'fees': [{'cost': 0.000190548, 'currency': 'DOT'}]}
open_price = data['info']['avgPx']
print("开仓平均价", open_price)
# 止盈价
closing_price = float(open_price) * float((1 + 0.005))
closing_price = common.roundVal(closing_price, open_price)
print("止盈价", closing_price)
# 止损价
stop_loss_price = float(open_price) * float((1 - 0.01))
stop_loss_price = common.roundVal(stop_loss_price, open_price)
print("止损价", stop_loss_price)
property_val = float(data['info']['accFillSz']) + \
float(data['info']['fee'])
# 相同位数
property_val = common.roundValCeil(property_val, data['info']['accFillSz'])
print("可平仓资产", property_val)
# closed_orders = exchange.fetchClosedOrders('DOT/USDT', limit=2)
# print('closed_orders', closed_orders)
# print(exchange.fetchBalance())
# 可以用,限价单
# time.sleep(1)
# data = exchange.createLimitSellOrder(
# 'DOT/USDT', property_val, closing_price, {"tdMode": "cross", 'ccy': 'USDT', "reduceOnly": True})
# print(data)
# print(type(data))
# 止损价
# 止盈价
exchange_params = {
'ccy': "USDT",
'reduceOnly': True,
'tdMode': "cross",
'tpOrdPx': "-1",
'tpTriggerPx': closing_price,
'slOrdPx': "-1",
'slTriggerPx': stop_loss_price,
}
print('---------止损价 执行----------------------------------')
data = exchange.create_order(
'DOT/USDT', 'limit', 'sell', property_val, closing_price, exchange_params)
print(data)
print(type(data))
# print('---------止盈价 执行----------------------------------')
# exchange_params = {
# 'stopPrice': closing_price,
# 'type': 'stopLimit',
# }
# data = exchange.create_order(
# 'DOT/USDT', 'limit', 'sell', property_val, closing_price, exchange_params)
# print(data)
# print(type(data))
def testK_buy_close():
# 平多
data = exchange.create_limit_buy_order(
'DOT/USDT', 1, 5, {"tdMode": "cross"})
print(data)
print(type(data))
# closed_orders = exchange.fetchClosedOrders('BTC/USDT', limit=2)
# print(closed_orders)
# closed_orders = exchange.fetchMyTrades('ETH/USDT', limit=2)
# print(closed_orders)
def testK_sell_open():
# 做空开仓
# data = exchange.createMarketSellOrder(
# 'DOT/USDT', 1, {"tdMode": "cross", 'ccy': "USDT", })
# print(data)
# print(type(data))
# 数据
# {'info': {'clOrdId': 'e847386590ce4dBC58e8b0afb0fe70cc', 'ordId': '554437054223302656', 'sCode': '0', 'sMsg': 'Order placed', 'tag': 'e847386590ce4dBC'}, 'id': '554437054223302656', 'clientOrderId': 'e847386590ce4dBC58e8b0afb0fe70cc', 'timestamp': None, 'datetime': None, 'lastTradeTimestamp': None, 'symbol': 'DOT/USDT', 'type': 'market', 'timeInForce': None, 'postOnly': None, 'side': 'buy', 'price': None, 'stopPrice': None, 'triggerPrice': None, 'average': None, 'cost': None, 'amount': None, 'filled': None, 'remaining': None, 'status': None, 'fee': None, 'trades': [], 'reduceOnly': None, 'fees': []}
# # 查询委托单
# order_id = data['info']['ordId']
order_id = '554516809819832320'
data = exchange.fetchOrder(order_id, 'DOT/USDT')
print(data['info'])
# {'info': {'accFillSz': '0.190548', 'algoClOrdId': '', 'algoId': '', 'avgPx': '5.248', 'cTime': '1678441709955', 'cancelSource': '', 'cancelSourceReason': '', 'category': 'normal', 'ccy': 'USDT', 'clOrdId': 'e847386590ce4dBCeaddfd1494dc7080', 'fee': '-0.000190548', 'feeCcy': 'DOT', 'fillPx': '5.248', 'fillSz': '0.190548', 'fillTime': '1678441709957', 'instId': 'DOT-USDT', 'instType': 'MARGIN', 'lever': '10', 'ordId': '554359943143833600', 'ordType': 'market', 'pnl': '0', 'posSide': 'net', 'px': '', 'quickMgnType': '', 'rebate': '0', 'rebateCcy': 'USDT', 'reduceOnly': 'false', 'side': 'buy', 'slOrdPx': '', 'slTriggerPx': '', 'slTriggerPxType': '', 'source': '', 'state': 'filled', 'sz': '1', 'tag': 'e847386590ce4dBC', 'tdMode': 'cross', 'tgtCcy': '', 'tpOrdPx': '', 'tpTriggerPx': '', 'tpTriggerPxType': '', 'tradeId': '81184616', 'uTime': '1678441709960'}, 'id': '554359943143833600', 'clientOrderId': 'e847386590ce4dBCeaddfd1494dc7080', 'timestamp': 1678441709955, 'datetime': '2023-03-10T09:48:29.955Z', 'lastTradeTimestamp': 1678441709957, 'symbol': 'DOT/USDT', 'type': 'market', 'timeInForce': 'IOC', 'postOnly': None, 'side': 'buy', 'price': 5.248, 'stopPrice': None, 'triggerPrice': None, 'average': 5.248, 'cost': 0.999995904, 'amount': 1.0, 'filled': 0.190548, 'remaining': 0.809452, 'status': 'closed', 'fee': {'cost': 0.000190548, 'currency': 'DOT'}, 'trades': [], 'reduceOnly': False, 'fees': [{'cost': 0.000190548, 'currency': 'DOT'}]}
open_price = data['info']['avgPx']
print("开仓平均价", open_price)
# 止盈价
closing_price = float(open_price) * float((1 - 0.005))
closing_price = common.roundVal(closing_price, open_price)
print("止盈价", closing_price)
# 止损价
stop_loss_price = float(open_price) * float((1 + 0.01))
stop_loss_price = common.roundVal(stop_loss_price, open_price)
print("止损价", stop_loss_price)
property_val = float(data['info']['accFillSz'])
# 相同位数
print("可平仓资产", property_val)
# 止损价
# 止盈价
exchange_params = {
'ccy': "USDT",
'reduceOnly': True,
'tdMode': "cross",
'tpOrdPx': "-1",
'tpTriggerPx': closing_price,
'slOrdPx': "-1",
'slTriggerPx': stop_loss_price,
}
print('---------止损价 执行----------------------------------')
data = exchange.create_order(
'DOT/USDT', 'limit', 'buy', property_val, closing_price, exchange_params)
print(data)
print(type(data))
def testK_sell_close():
# 平多
data = exchange.create_limit_buy_order(
'DOT/USDT', 1, 5, {"tdMode": "cross"})
print(data)
print(type(data))
# closed_orders = exchange.fetchClosedOrders('BTC/USDT', limit=2)
# print(closed_orders)
# closed_orders = exchange.fetchMyTrades('ETH/USDT', limit=2)
# print(closed_orders)
if __name__ == "__main__":
func = sys.argv[1]
if func == 'long':
longRun()
elif func == 'run':
debug()
elif func == 'test':
testKdan()
elif func == 't_get_trade':
t_get_trade()
elif func == 't_buy_open':
btc_test()
elif func == 't_buy_close':
testK_buy_close()
elif func == 't_sell_open':
testK_sell_open()
elif func == 't_sell_cloe':
testK_sell_close()
else:
print('error')
@@ -0,0 +1,102 @@
import ccxt
import talib
import sys
import os
import time
import pandas as pd
import pandas_ta as ta
from pprint import pprint
sys.path.append(os.getcwd() + "/plugins/cryptocurrency_trade/strategy")
import common
# cd /www/server/mdserver-web && source bin/activate
# python3 plugins/cryptocurrency_trade/ccxt/strategy/rsi_robot.py run
pd.set_option('display.max_rows', None)
exchange = common.initEx()
# 查看隐形方法
# print(dir(exchange))
exchange.load_markets()
entry_rsi = 30
exit_rsi = 40
symbol = 'XRP/USDT'
timeframe = '15m'
tf_mult = exchange.parse_timeframe(timeframe) * 1000
def indicators(data):
data['rsi'] = data.ta.rsi(length=10)
data['ema'] = data.ta.ema(length=200)
# close_p = data['close'].values
# data['rsi'] = talib.RSI(close_p, timeperiod=10)
# data['ema'] = talib.EMA(close_p, timeperiod=200)
return data
def check_buy_sell_signals(df):
last_row_index = len(df.index) - 1
lastest_rsi = round(df['rsi'].iloc[-1], 2)
lastest_price = round(df['close'].iloc[-1], 5)
lastest_ema = round(df['ema'].iloc[-1], 5)
lastest_ts = df['timestamp'].iloc[-1]
msg = "lastest_rsi:" + str(lastest_rsi) + " < entry_rsi:" + str(entry_rsi)
msg += ",lastest_price:" + \
str(lastest_price) + " > lastest_ema:" + str(lastest_ema)
print(msg)
long_cond = (lastest_rsi < entry_rsi) and (lastest_price > lastest_ema)
if long_cond:
print("买入")
order = exchange.create_market_buy_order(symbol, 1)
closed_orders = exchange.fetchClosedOrders(symbol, limit=2)
if len(closed_orders) > 0:
print("closed_orders:", closed_orders)
most_recent_closed_order = closed_orders[-1]
diff = lastest_ts - most_recent_closed_order['timestamp']
last_buy_signal_cnt = int(diff / tf_mult)
exit_cond = (lastest_rsi > exit_rsi) and (last_buy_signal_cnt > 10)
if exit_cond:
print("卖出")
order = exchange.create_market_sell_order(symbol, 1)
return
def runBot():
bars = exchange.fetch_ohlcv(symbol, timeframe=timeframe, limit=200)
df = pd.DataFrame(bars[:], columns=['timestamp',
'open', 'high', 'low', 'close', 'volume'])
df['dt'] = pd.to_datetime(df['timestamp'], unit='ms')
df = indicators(df).tail(30)
check_buy_sell_signals(df)
def longRunBot():
while True:
runBot()
time.sleep(10)
if __name__ == "__main__":
func = sys.argv[1]
if func == 'run':
longRunBot()
else:
print('error')
@@ -0,0 +1,536 @@
# cd /www/server/mdserver-web && source bin/activate
# python3 plugins/cryptocurrency_trade/ccxt/strategy/vega_trade.py run
# python3 plugins/cryptocurrency_trade/ccxt/strategy/vega_trade.py long
# 动量策略交易
################
import ccxt
import talib
import sys
import os
import time
import json
import pandas as pd
# import pandas_ta as ta
from pprint import pprint
import numpy as np
sys.path.append(os.getcwd() + "/plugins/cryptocurrency_trade/strategy")
import common
sys.path.append(os.getcwd() + "/class/core")
import mw
exchange = common.initEx()
exchange.load_markets()
# 默认开仓数据
# default_open_num = 70
# default_sell_num = 0.003
default_open = {
'BTC/USDT': 70,
'XRP/USDT': 70,
}
default_sell = {
'BTC/USDT': 0.003,
'XRP/USDT': 185,
}
# 做多开仓
def onBuyOrderTry(symbol, stop_loss_price, profit=0.005, timeframe='15m'):
# 信号只在一个周期内执行一次|start
lock_file = common.getServerDir() + '/signal.json'
if not os.path.exists(lock_file):
mw.writeFile(lock_file, '{}')
stype = symbol.replace('/', '_') + '_' + timeframe
trigger_time = common.toUnixTimeSecond(timeframe)
lock_data = json.loads(mw.readFile(lock_file))
if stype in lock_data:
diff_time = time.time() - lock_data[stype]['do_time']
if diff_time >= trigger_time:
lock_data[stype]['do_time'] = time.time()
else:
return False, 0, 0
else:
lock_data[stype] = {'do_time': time.time()}
mw.writeFile(lock_file, json.dumps(lock_data))
# 信号只在一个周期内执行一次|end
common.writeLogEx('------做多----------------------------------', symbol)
default_open_num = default_open[symbol]
# 做多开仓 | 市价
data = exchange.createMarketBuyOrder(
symbol, default_open_num, {"tdMode": "cross"})
common.writeLogEx('开仓数据:', symbol)
common.writeLogEx(json.dumps(data), symbol)
order_id = data['info']['ordId']
order_data = exchange.fetchOrder(order_id, symbol)
common.writeLogEx('订单数据:', symbol)
common.writeLogEx(json.dumps(order_data), symbol)
# 实际开场平均价
open_price = order_data['info']['avgPx']
# 修正小数点位数
open_price = common.roundVal(open_price, stop_loss_price)
common.writeLogEx('实际开仓价:' + str(open_price), symbol)
# 做多-止损价大于开仓价,重设止损价
if float(stop_loss_price) <= float(open_price):
stop_loss_price = float(open_price) * float((1 - 0.003))
# property_val = float(order_data['info']['accFillSz']) + float(order_data['info']['fee'])
property_val = common.addition(order_data['info'][
'accFillSz'], order_data['info']['fee'])
property_val = float(property_val)
# 可平仓的数量
# property_val = common.roundValCeil(
# property_val, order_data['info']['accFillSz'])
common.writeLogEx('可平仓资产:' + str(property_val), symbol)
# 止盈价
diff = float(open_price) - float(stop_loss_price)
closing_price = float(open_price) + (diff * 1.5)
# closing_price = float(open_price) * float((1 + profit))
# # 选择盈利多的
# if closing_price_c > closing_price:
# closing_price = closing_price_c
closing_price = common.roundVal(closing_price, open_price)
stop_loss_price = common.roundVal(stop_loss_price, open_price)
common.writeLogEx('止盈价:' + str(closing_price), symbol)
common.writeLogEx('止损价:' + str(stop_loss_price), symbol)
# 设置 - 止损价/止盈价
sl_exchange_params = {
'ccy': "USDT",
'reduceOnly': True,
'tdMode': "cross",
'slOrdPx': "-1",
'slTriggerPx': stop_loss_price,
}
# 止损条件单
common.writeLogEx('止损参数:' + json.dumps([symbol, 'limit', 'sell',
property_val, stop_loss_price, sl_exchange_params]), symbol)
sl_cond_data = exchange.create_order(
symbol, 'limit', 'sell', property_val, stop_loss_price, sl_exchange_params)
common.writeLogEx('止损价数据:', symbol)
common.writeLogEx(json.dumps(sl_cond_data), symbol)
# 止赢条件单
tp_exchange_params = {
'ccy': "USDT",
'reduceOnly': True,
'tdMode': "cross",
'tpOrdPx': "-1",
'tpTriggerPx': closing_price,
}
common.writeLogEx('止盈参数:' + json.dumps([symbol, 'limit', 'sell',
property_val, closing_price, tp_exchange_params]), symbol)
tp_cond_data = exchange.create_order(
symbol, 'limit', 'sell', property_val, closing_price, tp_exchange_params)
common.writeLogEx('止盈数据:', symbol)
common.writeLogEx(json.dumps(tp_cond_data), symbol)
common.writeLogEx('------做多 end----------------------------------', symbol)
return True, open_price, closing_price
def onBuyOrder(symbol, stop_loss_price, profit=0.005, timeframe='15m'):
# 做多开仓
# profit 百分比
try:
return onBuyOrderTry(symbol, stop_loss_price, profit, timeframe)
except Exception as e:
common.writeLogErrorEx(mw.getTracebackInfo(), symbol)
return False, 0, 0
def onSellOrderTry(symbol, stop_loss_price, profit=0.005, timeframe='15m'):
# 信号只在一个周期内执行一次|start
lock_file = common.getServerDir() + '/signal.json'
if not os.path.exists(lock_file):
mw.writeFile(lock_file, '{}')
stype = symbol.replace('/', '_') + '_' + timeframe
trigger_time = common.toUnixTimeSecond(timeframe)
lock_data = json.loads(mw.readFile(lock_file))
if stype in lock_data:
diff_time = time.time() - lock_data[stype]['do_time']
if diff_time >= trigger_time:
lock_data[stype]['do_time'] = time.time()
else:
return False, 0, 0
else:
lock_data[stype] = {'do_time': time.time()}
mw.writeFile(lock_file, json.dumps(lock_data))
# 信号只在一个周期内执行一次|end
common.writeLogEx('------做空----------------------------------', symbol)
# 计算借币卖币多多少,以USDT为基准
# sell_num = float(default_open_num) / float(stop_loss_price)
# sell_num = round(sell_num, 8)
# sell_num = default_sell_num
sell_num = default_sell[symbol]
# 做空开仓 | 市价
data = exchange.createMarketSellOrder(
symbol, sell_num, {"tdMode": "cross", 'ccy': "USDT"})
common.writeLogEx('开仓数据:', symbol)
common.writeLogEx(json.dumps(data), symbol)
order_id = data['info']['ordId']
order_data = exchange.fetchOrder(order_id, symbol)
common.writeLogEx('订单数据:', symbol)
common.writeLogEx(json.dumps(order_data), symbol)
# 实际开场平均价
open_price = order_data['info']['avgPx']
# 修正
open_price = common.roundVal(open_price, stop_loss_price)
common.writeLogEx('实际开仓价:' + str(open_price), symbol)
common.writeLogEx('可平仓资产:' + str(sell_num), symbol)
# 做空-止损价小于开仓价,重设止损价
if float(stop_loss_price) <= float(open_price):
stop_loss_price = float(open_price) * float((1 + 0.003))
# 止盈价
diff = float(stop_loss_price) - float(open_price)
closing_price = float(open_price) - (diff * 1.5)
# closing_price = float(open_price) * float((1 - profit))
# 选择盈利多的
# if closing_price_c < closing_price:
# closing_price = closing_price_c
closing_price = common.roundVal(closing_price, open_price)
stop_loss_price = common.roundVal(stop_loss_price, open_price)
common.writeLogEx('止盈价:' + str(closing_price), symbol)
common.writeLogEx('止损价:' + str(stop_loss_price), symbol)
# 设置 - 止损价
sl_exchange_params = {
'ccy': "USDT",
'reduceOnly': True,
'tdMode': "cross",
'slOrdPx': "-1",
'slTriggerPx': stop_loss_price,
}
sl_amount = common.multiply(stop_loss_price, sell_num)
# 解决平仓时,未全部平仓
sl_amount = common.addition(sl_amount, 0.1)
common.writeLogEx('止损总价值:' + str(sl_amount), symbol)
common.writeLogEx('止损参数:' + json.dumps([symbol, 'limit', 'buy', float(
sl_amount), stop_loss_price, sl_exchange_params]), symbol)
sl_cond_data = exchange.create_order(
symbol, 'limit', 'buy', float(sl_amount), stop_loss_price, sl_exchange_params)
common.writeLogEx('止损价数据:', symbol)
common.writeLogEx(json.dumps(sl_cond_data), symbol)
tp_exchange_params = {
'ccy': "USDT",
'reduceOnly': True,
'tdMode': "cross",
'tpOrdPx': "-1",
'tpTriggerPx': closing_price,
}
# 设置 -止盈价
# tp_amount = closing_price * sell_num
tp_amount = common.multiply(closing_price, sell_num)
# 解决平仓时,未全部平仓
tp_amount = common.addition(tp_amount, 0.1)
common.writeLogEx('止盈总价值:' + str(tp_amount), symbol)
common.writeLogEx('止盈参数:' + json.dumps([symbol, 'limit', 'buy', float(
tp_amount), closing_price, tp_exchange_params]), symbol)
tp_cond_data = exchange.create_order(
symbol, 'limit', 'buy', float(tp_amount), closing_price, tp_exchange_params)
common.writeLogEx('止盈价数据:', symbol)
common.writeLogEx(json.dumps(tp_cond_data), symbol)
common.writeLogEx('------做空 end----------------------------------', symbol)
return True, open_price, closing_price
def onSellOrder(symbol, stop_loss_price, profit=0.005, timeframe='15m'):
# 做空开仓
# profit 百分比
try:
return onSellOrderTry(symbol, stop_loss_price, profit, timeframe)
except Exception as e:
common.writeLogErrorEx(mw.getTracebackInfo(), symbol)
return False, 0, 0
def getOnlineData(symbol, input_tf="15m", limit=500):
bars = exchange.fetch_ohlcv(symbol, timeframe=input_tf, limit=500)
df = pd.DataFrame(bars[:], columns=['timestamp',
'open', 'high', 'low', 'close', 'volume'])
df['dt'] = pd.to_datetime(df['timestamp'], unit='ms')
df.set_index('dt', inplace=True)
df.index = df.index.tz_localize('UTC').tz_convert('Asia/Shanghai')
return df
def isKdj(last, last_pre):
# 判断是否是金叉
if (float(last_pre['macd']) < 0) and (float(last['macd']) > 0):
return True
return False
def isDeadFork(last, last_pre):
# 判断是否是死叉
if (float(last_pre['macd']) > 0) and (float(last['macd']) < 0):
return True
return False
def getTarget(df):
close = df['close'].values
# vega
df['ema144'] = talib.EMA(np.array(close), timeperiod=144)
df['ema169'] = talib.EMA(np.array(close), timeperiod=169)
df['ema288'] = talib.EMA(np.array(close), timeperiod=288)
df['ema388'] = talib.EMA(np.array(close), timeperiod=388)
df['rsi'] = talib.RSI(close, timeperiod=14)
return df
# 多头信号
def isBuyCrondSignal(last):
if last['ema'] > last['ma'] and (last['rsi'] > 50 and last['rsi'] < 70) and last['low'] >= last['ma'] and last['close'] > last['open']:
return True
return False
def isBuyFristSignal(data):
data = data.sort_values(by=['timestamp'], ascending=False)
# print(data)
data_len = len(data)
signal_num = 0
first_data = data.iloc[1]
# print(1, first_data['close'], first_data['ema'])
is_buy_signal = isBuyCrondSignal(first_data)
for x in range(2, data_len):
tmp = data.iloc[x]
# print(data.iloc[x])
# print(x, tmp['close'], tmp['ema'])
if isBuyCrondSignal(tmp):
signal_num = + 1
# print('signal_num:', signal_num)
if (tmp['ema'] < tmp['ma']):
break
if str(tmp['ema']) == 'nan':
break
print("is_buy_signal:", is_buy_signal, 'signal_num:', signal_num)
if is_buy_signal and signal_num == 0:
return True
return False
# 空头信号
def isSellCrondSignal(last):
if last['ema'] < last['ma'] and (last['rsi'] > 30 and last['rsi'] < 50) and last['high'] <= last['ema'] and last['close'] < last['open']:
return True
return False
def isSellFristSignal(data):
data = data.sort_values(by=['timestamp'], ascending=False)
# print(data)
data_len = len(data)
signal_num = 0
first_data = data.iloc[1]
# print(1, first_data['close'], first_data['ema'])
is_sell_signal = isSellCrondSignal(first_data)
for x in range(2, data_len):
tmp = data.iloc[x]
# print(data.iloc[x])
# print(x, tmp['close'], tmp['ema'])
if isSellCrondSignal(tmp):
signal_num = + 1
# print('signal_num:', signal_num)
if (tmp['ema'] < tmp['ma']):
break
if str(tmp['ema']) == 'nan':
break
print("is_sell_signal:", is_sell_signal, 'signal_num:', signal_num)
if is_sell_signal and signal_num == 0:
return True
return False
def isDownTrendCover(data, tag, timeframe):
# print(tag, timeframe, "开始检测是否下跌趋势")
# 下跌趋势回调
key_data = data.tail(2)
last_pre = key_data.iloc[0]
last = key_data.iloc[1]
pdata = data.tail(11)
for x in range(10):
t = pdata.iloc[x]
if t['low'] > t['ema388']:
print(tag, timeframe, "上升震荡行情过滤")
# print(t)
return False
if last['ema144'] > last['ema388']:
return False
print(tag, timeframe, "检查是下跌趋势!")
# 检查是否是下跌趋势
if last['high'] > last['ema388']:
return True
return False
def isUpTrendAndCover(data, tag, timeframe):
# print(tag, timeframe, "开始检测是否上升趋势")
# 上升趋势回调
key_data = data.tail(2)
# print(key_data)
last_pre = key_data.iloc[0]
last = key_data.iloc[1]
pdata = data.tail(11)
for x in range(10):
t = pdata.iloc[x]
if t['low'] < t['ema144']:
print(tag, timeframe, "上升震荡行情过滤")
return False
if last['ema144'] < last['ema388']:
return False
print(tag, timeframe, "检查是上升趋势")
# 检查是否是上升趋势
if last['low'] < last['ema144']:
return True
return False
def vegaTrade(data, tag, timeframe):
data = getTarget(data)
# print(data)
key_data = data.tail(2)
# print(key_data)
# last_pre = key_data.iloc[0]
last = key_data.iloc[1]
# print(last)
obj = common.MsgTpl()
symbol = tag.upper() + '/USDT'
obj.setName(symbol)
obj.setStrategyName("VEGA交易策略|仅具有指导作用")
obj.setTimeFrame(timeframe)
obj.setOpenTime(last['addtime'])
if isUpTrendAndCover(data, tag, timeframe):
obj.setStrategicDt('buy')
obj.setContent("VEGA上升趋势!回调做多~建议!")
msg = obj.toText()
common.notifyMsg(msg, timeframe, tag)
common.writeLog(msg)
if isDownTrendCover(data, tag, timeframe):
obj.setStrategicDt('sell')
obj.setContent("Vega下跌趋势!回调做空~建议!")
msg = obj.toText()
common.notifyMsg(msg, timeframe, tag)
common.writeLog(msg)
def mainProcess(tag, timeframe='5m'):
symbol = tag.upper() + '/USDT'
data = common.getDataFromDb_DF(timeframe, tag.lower())
vegaTrade(data, tag, timeframe)
return True
def foreachList():
tag_list = ['btc', 'xrp', 'eth', 'ltc', 'okb']
for tag in tag_list:
trame_list = ['5m', '15m', '1h', '4h']
for tf in trame_list:
mainProcess(tag, tf)
# time.sleep(1)
def longRun():
while True:
try:
foreachList()
time.sleep(1)
except Exception as e:
print(mw.getTracebackInfo())
time.sleep(3)
def debug():
while True:
mainProcess('btc', '5m')
time.sleep(1)
if __name__ == "__main__":
func = sys.argv[1]
if func == 'long':
longRun()
elif func == 'run':
debug()
else:
print('error')
@@ -0,0 +1,128 @@
'''
pip install git+https://github.com/catalyst-team/catalyst@master --upgrade
cd /www/server/mdserver-web && python3 plugins/cryptocurrency_trade/ccxt/test/p1.py
cd /Users/midoks/Desktop/mwdev/server/mdserver-web && source bin/activate
python3 plugins/cryptocurrency_trade/ccxt/test/p1.py
'''
from datetime import datetime
import akshare as ak
import pandas as pd
import backtrader as bt
class BollStrategy(bt.Strategy): # BOLL策略程序
params = (("nk", 13), # 求均值的天数
('printlog', False),) # 打印log
def __init__(self): # 初始化
self.data_close = self.datas[0].close # 指定价格序列
# 初始化交易指令、买卖价格和手续费
self.order = None
self.buy_price = None
self.buy_comm = None
# Boll指标计算
self.top = bt.indicators.BollingerBands(
self.datas[0], period=self.params.nk).top
self.bot = bt.indicators.BollingerBands(
self.datas[0], period=self.params.nk).bot
# 添加移动均线指标
self.sma = bt.indicators.SimpleMovingAverage(
self.datas[0], period=self.params.nk)
def next(self): # 买卖策略
if self.order: # 检查是否有指令等待执行
return
# 检查是否持仓
"""
if not self.position: # 没有持仓
if self.data_close[0] > self.sma[0]: # 执行买入条件判断:收盘价格上涨突破20日均线
self.order = self.buy(size=100) # 执行买入
else:
if self.data_close[0] < self.sma[0]: # 执行卖出条件判断:收盘价格跌破20日均线
self.order = self.sell(size=100) # 执行卖出
"""
if not self.position: # 没有持仓
if self.data_close[0] < self.bot[0]: # 收盘价格跌破下轨
self.log("BUY CREATE, %.2f" % self.data_close[0])
self.order = self.buy() # 执行买入
else:
if self.data_close[0] > self.top[0]: # 收盘价格上涨突破上轨
self.log("SELL CREATE, %.2f" % self.data_close[0])
self.order = self.sell() # 执行卖出
def log(self, txt, dt=None, do_print=False): # 日志函数
if self.params.printlog or do_print:
dt = dt or self.datas[0].datetime.date(0)
print('%s, %s' % (dt.isoformat(), txt))
def notify_order(self, order): # 记录交易执行情况
# 如果order为submitted/accepted,返回空
if order.status in [order.Submitted, order.Accepted]:
return
# 指令为buy/sell,报告价格结果
if order.status in [order.Completed]:
if order.isbuy():
self.log(
f"买入:\n价格:{order.executed.price},\
成本:{order.executed.value},\
手续费:{order.executed.comm}"
)
self.buyprice = order.executed.price
self.buycomm = order.executed.comm
else:
self.log(
f"卖出:\n价格:{order.executed.price},\
成本: {order.executed.value},\
手续费{order.executed.comm}"
)
self.bar_executed = len(self)
elif order.status in [order.Canceled, order.Margin, order.Rejected]:
self.log("交易失败") # 指令取消/交易失败, 报告结果
self.order = None
def notify_trade(self, trade): # 记录交易收益情况
if not trade.isclosed:
return
self.log(f"策略收益:\n毛收益 {trade.pnl:.2f}, 净收益 {trade.pnlcomm:.2f}")
def stop(self): # 回测结束后输出结果
self.log("(BOLL线: %2d日) 期末总资金 %.2f" %
(self.params.nk, self.broker.getvalue()), do_print=True)
code = "600036" # 股票代码
start_cash = 1000000 # 初始自己为1000000
stake = 100 # 单次交易数量为1手
commfee = 0.0005 # 佣金为万5
sdate = '20210101' # 回测时间段
edate = '20220930'
cerebro = bt.Cerebro() # 创建回测系统实例
# 利用AKShare获取股票的前复权数据的前6列
df_qfq = ak.stock_zh_a_hist(
symbol=code, adjust="qfq", start_date=sdate, end_date=edate).iloc[:, :6]
# 处理字段命名,以符合Backtrader的要求
df_qfq.columns = ['date', 'open', 'close', 'high', 'low', 'volume', ]
# 把date作为日期索引,以符合Backtrader的要求
df_qfq.index = pd.to_datetime(df_qfq['date'])
start_date = datetime.strptime(sdate, "%Y%m%d") # 转换日期格式
end_date = datetime.strptime(edate, "%Y%m%d")
# start_date=datetime(2022,1,4)
# end_date=datetime(2022,9,16)
data = bt.feeds.PandasData(
dataname=df_qfq, fromdate=start_date, todate=end_date) # 规范化数据格式
cerebro.adddata(data) # 加载数据
cerebro.addstrategy(BollStrategy, nk=13, printlog=True) # 加载交易策略
cerebro.broker.setcash(start_cash) # broker设置资金
cerebro.broker.setcommission(commission=commfee) # broker手续费
cerebro.addsizer(bt.sizers.FixedSize, stake=stake) # 设置买入数量
print("期初总资金: %.2f" % start_cash)
cerebro.run() # 运行回测
end_value = cerebro.broker.getvalue() # 获取回测结束后的总资金
print("期末总资金: %.2f" % end_value)
cerebro.plot()
@@ -0,0 +1,154 @@
'''
pip install git+https://github.com/catalyst-team/catalyst@master --upgrade
cd /www/server/mdserver-web && python3 plugins/cryptocurrency_trade/ccxt/test/p1.py
cd /Users/midoks/Desktop/mwdev/server/mdserver-web && source bin/activate
python3 plugins/cryptocurrency_trade/ccxt/test/p1.py
'''
from datetime import datetime
import akshare as ak
import pandas as pd
import backtrader as bt
import sys
import os
sys.path.append(os.getcwd() + "/plugins/cryptocurrency_trade/ccxt/strategy")
import common
class BollStrategy(bt.Strategy): # BOLL策略程序
params = (("nk", 13), # 求均值的天数
('printlog', False),) # 打印log
def __init__(self): # 初始化
self.data_close = self.datas[0].close # 指定价格序列
# 初始化交易指令、买卖价格和手续费
self.order = None
self.buy_price = None
self.buy_comm = None
# Boll指标计算
self.top = bt.indicators.BollingerBands(
self.datas[0], period=self.params.nk).top
self.bot = bt.indicators.BollingerBands(
self.datas[0], period=self.params.nk).bot
# 添加移动均线指标
self.sma = bt.indicators.SimpleMovingAverage(
self.datas[0], period=self.params.nk)
def next(self): # 买卖策略
if self.order: # 检查是否有指令等待执行
return
# 检查是否持仓
"""
if not self.position: # 没有持仓
if self.data_close[0] > self.sma[0]: # 执行买入条件判断:收盘价格上涨突破20日均线
self.order = self.buy(size=100) # 执行买入
else:
if self.data_close[0] < self.sma[0]: # 执行卖出条件判断:收盘价格跌破20日均线
self.order = self.sell(size=100) # 执行卖出
"""
if not self.position: # 没有持仓
if self.data_close[0] < self.bot[0]: # 收盘价格跌破下轨
self.log("BUY CREATE, %.2f" % self.data_close[0])
self.order = self.buy() # 执行买入
else:
if self.data_close[0] > self.top[0]: # 收盘价格上涨突破上轨
self.log("SELL CREATE, %.2f" % self.data_close[0])
self.order = self.sell() # 执行卖出
def log(self, txt, dt=None, do_print=False): # 日志函数
if self.params.printlog or do_print:
dt = dt or self.datas[0].datetime.date(0)
print('%s, %s' % (dt.isoformat(), txt))
def notify_order(self, order): # 记录交易执行情况
# 如果order为submitted/accepted,返回空
if order.status in [order.Submitted, order.Accepted]:
return
# 指令为buy/sell,报告价格结果
if order.status in [order.Completed]:
if order.isbuy():
self.log(
f"买入:\n价格:{order.executed.price},\
成本:{order.executed.value},\
手续费:{order.executed.comm}"
)
self.buyprice = order.executed.price
self.buycomm = order.executed.comm
else:
self.log(
f"卖出:\n价格:{order.executed.price},\
成本: {order.executed.value},\
手续费{order.executed.comm}"
)
self.bar_executed = len(self)
elif order.status in [order.Canceled, order.Margin, order.Rejected]:
self.log("交易失败") # 指令取消/交易失败, 报告结果
self.order = None
def notify_trade(self, trade): # 记录交易收益情况
if not trade.isclosed:
return
self.log(f"策略收益:\n毛收益 {trade.pnl:.2f}, 净收益 {trade.pnlcomm:.2f}")
def stop(self): # 回测结束后输出结果
self.log("(BOLL线: %2d日) 期末总资金 %.2f" %
(self.params.nk, self.broker.getvalue()), do_print=True)
code = "600036" # 股票代码
start_cash = 1000000 # 初始自己为1000000
stake = 100 # 单次交易数量为1手
commfee = 0.0005 # 佣金为万5
sdate = '20210101' # 回测时间段
edate = '20220930'
cerebro = bt.Cerebro() # 创建回测系统实例
# 利用AKShare获取股票的前复权数据的前6列
# df_qfq = ak.stock_zh_a_hist(
# symbol=code, adjust="qfq", start_date=sdate, end_date=edate).iloc[:, :6]
# 日期 开盘 收盘 最高 最低 成交量
# 0 2021-01-04 40.46 40.40 41.01 39.25 1549523
# 1 2021-01-05 39.99 39.41 40.03 38.67 1387177
# 2 2021-01-06 39.33 41.38 41.43 39.23 1200646
# 3 2021-01-07 41.52 43.13 43.20 41.49 1078322
# 4 2021-01-08 43.52 43.83 44.25 43.04 1299595
# .. ... ... ... ... ... ...
# 420 2022-09-26 34.02 33.95 34.52 33.84 525491
# 421 2022-09-27 33.89 33.90 34.05 33.44 475414
# 422 2022-09-28 33.79 33.67 34.00 33.42 487299
# 423 2022-09-29 33.99 33.15 34.32 33.00 617859
# 424 2022-09-30 33.26 33.65 33.95 33.12 539717
tag = 'btc'
symbol = tag.upper() + '/USDT'
df_qfq = common.getDataFromDb_DF('15m', tag.lower())
print(df_qfq)
# # 处理字段命名,以符合Backtrader的要求
# df_qfq.columns = ['date', 'open', 'close', 'high', 'low', 'volume', ]
# # 把date作为日期索引,以符合Backtrader的要求
# df_qfq.index = pd.to_datetime(df_qfq['date'])
# start_date = datetime.strptime(sdate, "%Y%m%d") # 转换日期格式
# end_date = datetime.strptime(edate, "%Y%m%d")
start_date = datetime(2023, 4, 6)
end_date = datetime(2023, 4, 9)
data = bt.feeds.PandasData(dataname=df_qfq, fromdate=start_date,
todate=end_date) # 规范化数据格式
cerebro.adddata(data) # 加载数据
cerebro.addstrategy(BollStrategy, nk=13, printlog=True) # 加载交易策略
cerebro.broker.setcash(start_cash) # broker设置资金
cerebro.broker.setcommission(commission=commfee) # broker手续费
cerebro.addsizer(bt.sizers.FixedSize, stake=stake) # 设置买入数量
print("期初总资金: %.2f" % start_cash)
cerebro.run() # 运行回测
end_value = cerebro.broker.getvalue() # 获取回测结束后的总资金
print("期末总资金: %.2f" % end_value)
# cerebro.plot(style='candle')
@@ -0,0 +1,61 @@
# coding:utf-8
import pandas as pd
import matplotlib.pyplot as plt
from catalyst import run_algorithm
from catalyst.api import order, record, symbol
'''
cd /Users/midoks/Desktop/mwdev/server/mdserver-web && source bin/activate
cd /www/server/mdserver-web && source bin/activate && source activate catalys
cd /Users/midoks/Desktop/mwdev/server/mdserver-web && python3 plugins/cryptocurrency_trade/ccxt/test/p_test.py
catalyst ingest-exchange -x binance -i btc_usdt -f minute
cd /www/server/mdserver-web && python3 plugins/cryptocurrency_trade/ccxt/test/p_test.py
'''
def initialize(context):
# 初始化
context.asset = symbol('btc_usdt')
def handle_data(context, data):
# 循环策略
order(context.asset, 1)
record(btc=data.current(context.asset, 'price'))
def analyze(context, perf):
print(perf.portfolio_value)
ax1 = plt.subplot(211)
perf.portfolio_value.plot(ax=ax1)
ax1.set_ylabel('portfolio value')
ax2 = plt.subplot(212, sharex=ax1)
perf.btc.plot(ax=ax2)
ax2.set_ylabel('bitcoin value')
plt.show()
if __name__ == "__main__":
run_algorithm(
capital_base=10000,
data_frequency='daily',
initialize=initialize,
handle_data=handle_data,
analyze=analyze,
exchange_name='binance',
quote_currenty='usdt',
start=pd.to_datetime("2018-01-01", utc=True),
end=pd.to_datetime("2018-10-01", utc=True),
)
@@ -0,0 +1,9 @@
CREATE TABLE IF NOT EXISTS `ct_xx1_xx2` (
`addtime` BIGINT(20) not NULL,
`open` float NOT NULL,
`high` float NOT NULL,
`low` float NOT NULL,
`close` float NOT NULL,
`vol` float NOT NULL,
UNIQUE KEY `addtime` (`addtime`)
);
@@ -0,0 +1,11 @@
CREATE TABLE IF NOT EXISTS `ct_order_list` (
`id` BIGINT(20) not NULL,
'strategy_name' varchar(50) NULL,
`symbol` varchar(50) NOT NULL,
`fee` float NOT NULL,
`price` float NOT NULL,
`closing_price` float NOT NULL comment '',
`profit` float NOT NULL,
`source` TEXT,
`addtime` BIGINT(20) not NULL
);
@@ -0,0 +1,14 @@
[program:{$NAME}]
command=bash -c "cd {$RUN_ROOT} && source bin/activate && python3 {$ABS_FILE} long"
directory={$RUN_ROOT}
autorestart=true
startsecs=3
startretries=3
stdout_logfile={$SUP_ROOT}/log/{$NAME}.out.log
stderr_logfile={$SUP_ROOT}/log/{$NAME}.err.log
stdout_logfile_maxbytes=2MB
stderr_logfile_maxbytes=2MB
user=root
priority=999
numprocs=1
process_name=%(program_name)s
@@ -0,0 +1,14 @@
[program:{$NAME}]
command=bash -c "cd {$RUN_ROOT} && source bin/activate && python3 plugins/cryptocurrency_trade/ccxt/public_data/data.py long"
directory={$RUN_ROOT}
autorestart=true
startsecs=3
startretries=3
stdout_logfile={$SUP_ROOT}/log/{$NAME}.out.log
stderr_logfile={$SUP_ROOT}/log/{$NAME}.err.log
stdout_logfile_maxbytes=2MB
stderr_logfile_maxbytes=2MB
user=root
priority=999
numprocs=1
process_name=%(program_name)s
@@ -0,0 +1,350 @@
# coding:utf-8
import sys
import io
import os
import time
import re
import string
import subprocess
import json
web_dir = os.getcwd() + "/web"
if os.path.exists(web_dir):
sys.path.append(web_dir)
os.chdir(web_dir)
import core.mw as mw
app_debug = False
if mw.isAppleSystem():
app_debug = True
def getPluginName():
return 'cryptocurrency_trade'
def getPluginDir():
return mw.getPluginDir() + '/' + getPluginName()
def getServerDir():
return mw.getServerDir() + '/' + getPluginName()
def contentReplace(content):
service_path = mw.getServerDir()
content = content.replace('{$ROOT_PATH}', mw.getFatherDir())
content = content.replace('{$SERVER_PATH}', service_path)
content = content.replace(
'{$SERVER_APP}', service_path + '/' + getPluginName())
return content
def getArgs():
args = sys.argv[2:]
tmp = {}
args_len = len(args)
if args_len == 1:
t = args[0].strip('{').strip('}')
if t.strip() == '':
tmp = []
else:
t = t.split(':', 1)
tmp[t[0]] = t[1]
tmp[t[0]] = t[1]
elif args_len > 1:
for i in range(len(args)):
t = args[i].split(':', 1)
tmp[t[0]] = t[1]
return tmp
def checkArgs(data, ck=[]):
for i in range(len(ck)):
if not ck[i] in data:
return (False, mw.returnJson(False, '参数:(' + ck[i] + ')没有!'))
return (True, mw.returnJson(True, 'ok'))
def isSqlError(mysqlMsg):
# 检测数据库执行错误
mysqlMsg = str(mysqlMsg)
if "MySQLdb" in mysqlMsg:
return mw.returnJson(False, 'MySQLdb组件缺失! <br>进入SSH命令行输入: pip install mysql-python | pip install mysqlclient==2.0.3')
if "2002," in mysqlMsg:
return mw.returnJson(False, '数据库连接失败,请检查数据库服务是否启动!')
if "2003," in mysqlMsg:
return mw.returnJson(False, "Can't connect to MySQL server on '127.0.0.1' (61)")
if "using password:" in mysqlMsg:
return mw.returnJson(False, '数据库密码错误')
if "1045" in mysqlMsg:
return mw.returnJson(False, '连接错误!')
if "SQL syntax" in mysqlMsg:
return mw.returnJson(False, 'SQL语法错误!')
if "Connection refused" in mysqlMsg:
return mw.returnJson(False, '数据库连接失败,请检查数据库服务是否启动!')
if "1133," in mysqlMsg:
return mw.returnJson(False, '数据库用户不存在!')
if "1007," in mysqlMsg:
return mw.returnJson(False, '数据库已经存在!')
return None
def getConfigData():
cfg_path = getServerDir() + "/data.cfg"
if not os.path.exists(cfg_path):
mw.writeFile(cfg_path, '{}')
t = mw.readFile(cfg_path)
return json.loads(t)
def writeConf(data):
cfg_path = getServerDir() + "/data.cfg"
mw.writeFile(cfg_path, json.dumps(data))
return True
def getDbConf():
data = getConfigData()
if 'db' in data:
return mw.returnJson(True, 'ok', data['db'])
return mw.returnJson(False, 'ok', {})
def getUserConf():
data = getConfigData()
if 'user' in data:
return mw.returnJson(True, 'ok', data['user'])
return mw.returnJson(False, 'ok', {})
def restartSup():
cmd = 'python3 plugins/supervisor/index.py restart'
mw.execShell(cmd)
def restartSupDst(name):
cmd = 'python3 plugins/supervisor/index.py restart_job {"name":"' + \
name + '","status":"stop"}'
mw.execShell(cmd)
def syncDataAddTaskUninstall():
sup_path = mw.getServerDir() + '/supervisor'
if not os.path.exists(sup_path):
return mw.returnJson(False, '需要安装并启动supervisor插件')
name = "ct_task"
sup_task_dst = sup_path + '/conf.d/' + name + '.ini'
if os.path.exists(sup_task_dst):
mw.execShell('rm -rf ' + sup_task_dst)
restartSup()
return mw.returnJson(True, '删除同步数据任务成功!')
def syncDataAddTaskInstall():
sup_path = mw.getServerDir() + '/supervisor'
if not os.path.exists(sup_path):
return mw.returnJson(False, '需要安装并启动supervisor插件')
name = "ct_task"
sup_task_tpl = getPluginDir() + '/conf/sup_task.tpl'
sup_task_dst = sup_path + '/conf.d/' + name + '.ini'
content = mw.readFile(sup_task_tpl)
content = content.replace(
'{$RUN_ROOT}', mw.getServerDir() + '/mdserver-web')
content = content.replace(
'{$SUP_ROOT}', sup_path)
content = content.replace(
'{$NAME}', name)
mw.writeFile(sup_task_dst, content)
restartSup()
return mw.returnJson(True, '添加同步数据任务成功!')
def syncDataAddTask():
args = getArgs()
data_args = checkArgs(args, ['check'])
if not data_args[0]:
return data_args[1]
if args['check'] == "0":
return syncDataAddTaskUninstall()
return syncDataAddTaskInstall()
def syncDataDelete():
args = getArgs()
data_args = checkArgs(args, ['token'])
if not data_args[0]:
return data_args[1]
del_token = args['token']
data = getConfigData()
if 'token' in data:
data['token'].remove(del_token)
writeConf(data)
return mw.returnJson(True, '删除成功!')
# callback ---------------------------------- start
def get_datasource_logs(args):
log_file = getServerDir() + '/logs/datasource.log'
if not os.path.exists(log_file):
return '暂无日志'
data = mw.getLastLine(log_file, 10)
return data
def get_strategy_logs(args):
log_file = getServerDir() + '/logs/strategy.log'
if not os.path.exists(log_file):
return '暂无日志'
data = mw.getLastLine(log_file, 10)
return data
def save_body(args):
path = args['path']
encoding = args['encoding']
data = args['data']
tag = args['tag']
if not os.path.exists(path):
return mw.returnData(False, '文件不存在')
try:
if encoding == 'ascii':
encoding = 'utf-8'
data = data.encode(
encoding, errors='ignore').decode(encoding)
fp = open(path, 'w+', encoding=encoding)
fp.write(data)
fp.close()
set_strategy_restart({'id': tag})
return mw.returnData(True, '文件保存成功')
except Exception as ex:
return mw.returnData(False, '文件保存错误:' + str(ex))
def get_strategy_path(args):
abs_id = args['id']
name = "ct_strategy_" + abs_id
abs_file = get_strategy_absfile(abs_id)
return mw.returnData(True, abs_file)
def set_strategy_restart(args):
sup_path = mw.getServerDir() + '/supervisor'
if not os.path.exists(sup_path):
return mw.returnData(False, '需要安装并启动supervisor插件')
abs_id = args['id']
name = "ct_strategy_" + abs_id
sup_strategy_dst = sup_path + '/conf.d/' + name + '.ini'
if not os.path.exists(sup_strategy_dst):
return mw.returnData(False, '策略任务' + abs_id + '未添加!')
restartSupDst(name)
return mw.returnData(True, '重启策略任务' + abs_id + '成功!')
def set_strategy_status(args):
sup_path = mw.getServerDir() + '/supervisor'
if not os.path.exists(sup_path):
return mw.returnData(False, '需要安装并启动supervisor插件')
abs_id = args['id']
name = "ct_strategy_" + abs_id
sup_strategy_dst = sup_path + '/conf.d/' + name + '.ini'
if args['status'] == 'stop':
if os.path.exists(sup_strategy_dst):
os.remove(sup_strategy_dst)
restartSup()
return mw.returnData(True, '删除策略任务' + abs_id + '成功!')
abs_file = get_strategy_absfile(abs_id)
sup_strategy_tpl = getPluginDir() + '/conf/sup_strategy.tpl'
content = mw.readFile(sup_strategy_tpl)
content = content.replace(
'{$RUN_ROOT}', mw.getServerDir() + '/mdserver-web')
content = content.replace(
'{$SUP_ROOT}', sup_path)
content = content.replace(
'{$NAME}', name)
content = content.replace(
'{$ABS_FILE}', abs_file)
mw.writeFile(sup_strategy_dst, content)
restartSup()
return mw.returnData(True, '添加策略任务' + abs_id + '成功!')
def get_strategy_absfile(abs_id):
info = getPluginDir() + '/ccxt/strategy/info.json'
info = json.loads(mw.readFile(info))
path = getPluginDir() + '/ccxt/strategy'
for x in range(len(info)):
if info[x]['id'] == abs_id:
return path + '/' + info[x]['file']
return path + '/abs.py'
def get_strategy_list(args):
info = getPluginDir() + '/ccxt/strategy/info.json'
info = json.loads(mw.readFile(info))
st_path = mw.getServerDir() + '/supervisor/conf.d'
page = 1
page_size = 5
search = ''
data = {}
if 'page' in args:
page = int(args['page'])
if 'page_size' in args:
page_size = int(args['page_size'])
dlist_sum = len(info)
page_start = int((page - 1) * page_size)
page_end = page_start + page_size
if page_end >= dlist_sum:
ret_data = info[page_start:]
else:
ret_data = info[page_start:page_end]
for x in range(len(ret_data)):
strategy_dst = st_path + '/ct_strategy_' + ret_data[x]['id'] + '.ini'
if os.path.exists(strategy_dst):
ret_data[x]['status'] = 'start'
else:
ret_data[x]['status'] = 'stop'
data['data'] = ret_data
data['args'] = args
data['list'] = mw.getPage(
{'count': dlist_sum, 'p': page, 'row': page_size, 'tojs': 'getStrategyList'})
return data
# callback ---------------------------------- end
Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

+26
View File
@@ -0,0 +1,26 @@
<style type="text/css">
.conf_p span{width: 100px;}
.code{padding: 20px 5px;border: 1px solid #e1e1e1;background: #fcfcfc;border-radius: 4px;line-height: 24px;}
.code span {display: block;margin-left: 15px;margin-bottom: 0;}
</style>
<div class="bt-form">
<div class="bt-w-main">
<div class="bt-w-menu">
<p class="bgw" onclick="pluginService('cryptocurrency_trade');">服务</p>
<p onclick="dbConf();">数据库配置</p>
<p onclick="syncDataList();">同步数据配置</p>
<p onclick="userConf();">账户配置</p>
</div>
<div class="bt-w-con pd15">
<div class="soft-man-con"></div>
</div>
</div>
</div>
<script type="text/javascript">
// resetPluginWinWidth(480);
resetPluginWinHeight(400);
$.getScript( "/plugins/file?name=cryptocurrency_trade&f=static/js/cryptocurrency_trade.js",function(){
pluginService('cryptocurrency_trade');
});
</script>
+347
View File
@@ -0,0 +1,347 @@
# coding:utf-8
import sys
import io
import os
import time
import re
import string
import subprocess
import json
web_dir = os.getcwd() + "/web"
if os.path.exists(web_dir):
sys.path.append(web_dir)
os.chdir(web_dir)
import core.mw as mw
app_debug = False
if mw.isAppleSystem():
app_debug = True
def getPluginName():
return 'cryptocurrency_trade'
def getPluginDir():
return mw.getPluginDir() + '/' + getPluginName()
def getServerDir():
return mw.getServerDir() + '/' + getPluginName()
def contentReplace(content):
service_path = mw.getServerDir()
content = content.replace('{$ROOT_PATH}', mw.getFatherDir())
content = content.replace('{$SERVER_PATH}', service_path)
content = content.replace(
'{$SERVER_APP}', service_path + '/' + getPluginName())
return content
def getArgs():
args = sys.argv[2:]
tmp = {}
args_len = len(args)
if args_len == 1:
t = args[0].strip('{').strip('}')
if t.strip() == '':
tmp = []
else:
t = t.split(':', 1)
tmp[t[0]] = t[1]
tmp[t[0]] = t[1]
elif args_len > 1:
for i in range(len(args)):
t = args[i].split(':', 1)
tmp[t[0]] = t[1]
return tmp
def checkArgs(data, ck=[]):
for i in range(len(ck)):
if not ck[i] in data:
return (False, mw.returnJson(False, '参数:(' + ck[i] + ')没有!'))
return (True, mw.returnJson(True, 'ok'))
def isSqlError(mysqlMsg):
# 检测数据库执行错误
mysqlMsg = str(mysqlMsg)
if "MySQLdb" in mysqlMsg:
return mw.returnJson(False, 'MySQLdb组件缺失! <br>进入SSH命令行输入: pip install mysql-python | pip install mysqlclient==2.0.3')
if "2002," in mysqlMsg:
return mw.returnJson(False, '数据库连接失败,请检查数据库服务是否启动!')
if "2003," in mysqlMsg:
return mw.returnJson(False, "Can't connect to MySQL server on '127.0.0.1' (61)")
if "using password:" in mysqlMsg:
return mw.returnJson(False, '数据库密码错误')
if "1045" in mysqlMsg:
return mw.returnJson(False, '连接错误!')
if "SQL syntax" in mysqlMsg:
return mw.returnJson(False, 'SQL语法错误!')
if "Connection refused" in mysqlMsg:
return mw.returnJson(False, '数据库连接失败,请检查数据库服务是否启动!')
if "1133" in mysqlMsg:
return mw.returnJson(False, '数据库用户不存在!')
if "1007" in mysqlMsg:
return mw.returnJson(False, '数据库已经存在!')
return None
def initDreplace():
log_dir = getServerDir() + '/logs'
if not os.path.exists(log_dir):
d = mw.execShell('mkdir -p ' + log_dir)
data = getConfigData()
data['token'] = ['btc']
writeConf(data)
return True
def status():
initDreplace()
return 'start'
def start():
syncDataAddTaskInstall()
return 'ok'
def stop():
syncDataAddTaskUninstall()
return 'ok'
def op():
return 'ok'
def getConfigData():
cfg_path = getServerDir() + "/data.cfg"
if not os.path.exists(cfg_path):
mw.writeFile(cfg_path, '{}')
t = mw.readFile(cfg_path)
return json.loads(t)
def writeConf(data):
cfg_path = getServerDir() + "/data.cfg"
mw.writeFile(cfg_path, json.dumps(data))
return True
def getDbConf():
data = getConfigData()
if 'db' in data:
return mw.returnJson(True, 'ok', data['db'])
return mw.returnJson(False, 'ok', {})
def setDbConf():
args = getArgs()
data_args = checkArgs(args, ['db_host', 'db_port',
'db_name', 'db_user', 'db_pass'])
if not data_args[0]:
return data_args[1]
data = getConfigData()
data['db'] = args
writeConf(data)
db = mw.getMyORM()
db.setHost(args['db_host'])
db.setPort(args['db_port'])
db.setUser(args['db_user'])
db.setPwd(args['db_pass'])
testdata = db.query('select version()')
isError = isSqlError(testdata)
if isError != None:
return isError
return mw.returnJson(True, '保存成功,并连通成功!', [])
def getUserConf():
data = getConfigData()
if 'user' in data:
return mw.returnJson(True, 'ok', data['user'])
return mw.returnJson(False, 'ok', {})
def getUserConf():
data = getConfigData()
if 'user' in data:
try:
udata = mw.deDoubleCrypt('mw', data['user'])
udata = json.loads(udata)
return mw.returnJson(True, 'ok', udata)
except Exception as e:
pass
return mw.returnJson(False, 'ok', {})
def setUserConf():
args = getArgs()
data_args = checkArgs(args, ['app_key', 'secret',
'password', 'uid', 'exchange'])
if not data_args[0]:
return data_args[1]
data = getConfigData()
data['user'] = mw.enDoubleCrypt('mw', json.dumps(args))
writeConf(data)
return mw.returnJson(True, '保存成功!', [])
def syncDataList():
data = getConfigData()
name = "ct_task"
if 'token' in data:
rdata = {}
rdata['task_status'] = False
sup_path = mw.getServerDir() + '/supervisor'
sup_task_dst = sup_path + '/conf.d/' + name + '.ini'
if os.path.exists(sup_task_dst):
rdata['task_status'] = True
rdata['list'] = data['token']
return mw.returnJson(True, 'ok', rdata)
return mw.returnJson(False, 'ok')
def syncDataAdd():
args = getArgs()
data_args = checkArgs(args, ['token'])
if not data_args[0]:
return data_args[1]
add_token = args['token']
data = getConfigData()
if 'token' in data and data['token']:
if not add_token in data['token']:
data['token'].append(add_token)
else:
data['token'] = [add_token]
writeConf(data)
return mw.returnJson(True, '保存成功!')
def restartSup():
cmd = 'python3 plugins/supervisor/index.py restart'
mw.execShell(cmd)
def restartSupDst(name):
cmd = 'python3 plugins/supervisor/index.py restart_job {"name":"' + \
name + '","status":"stop"}'
mw.execShell(cmd)
def syncDataAddTaskUninstall():
sup_path = mw.getServerDir() + '/supervisor'
if not os.path.exists(sup_path):
return mw.returnJson(False, '需要安装并启动supervisor插件')
name = "ct_task"
sup_task_dst = sup_path + '/conf.d/' + name + '.ini'
if os.path.exists(sup_task_dst):
mw.execShell('rm -rf ' + sup_task_dst)
restartSup()
return mw.returnJson(True, '删除同步数据任务成功!')
def syncDataAddTaskInstall():
sup_path = mw.getServerDir() + '/supervisor'
if not os.path.exists(sup_path):
return mw.returnJson(False, '需要安装并启动supervisor插件')
name = "ct_task"
sup_task_tpl = getPluginDir() + '/conf/sup_task.tpl'
sup_task_dst = sup_path + '/conf.d/' + name + '.ini'
content = mw.readFile(sup_task_tpl)
content = content.replace(
'{$RUN_ROOT}', mw.getServerDir() + '/mdserver-web')
content = content.replace(
'{$SUP_ROOT}', sup_path)
content = content.replace(
'{$NAME}', name)
mw.writeFile(sup_task_dst, content)
restartSup()
return mw.returnJson(True, '添加同步数据任务成功!')
def syncDataAddTask():
args = getArgs()
data_args = checkArgs(args, ['check'])
if not data_args[0]:
return data_args[1]
if args['check'] == "0":
return syncDataAddTaskUninstall()
return syncDataAddTaskInstall()
def syncDataDelete():
args = getArgs()
data_args = checkArgs(args, ['token'])
if not data_args[0]:
return data_args[1]
del_token = args['token']
data = getConfigData()
if 'token' in data:
data['token'].remove(del_token)
writeConf(data)
return mw.returnJson(True, '删除成功!')
if __name__ == "__main__":
func = sys.argv[1]
if func == 'status':
print(status())
elif func == 'start':
print(start())
elif func == 'stop':
print(stop())
elif func == 'restart':
print(op())
elif func == 'reload':
print(op())
elif func == 'get_db_conf':
print(getDbConf())
elif func == 'set_db_conf':
print(setDbConf())
elif func == 'get_user_conf':
print(getUserConf())
elif func == 'set_user_conf':
print(setUserConf())
elif func == 'sync_data_list':
print(syncDataList())
elif func == 'sync_data_add':
print(syncDataAdd())
elif func == 'sync_data_delete':
print(syncDataDelete())
elif func == 'sync_data_add_task':
print(syncDataAddTask())
else:
print('error')
+36
View File
@@ -0,0 +1,36 @@
{
"hook":[
{
"tag":"menu",
"menu": {
"title":"量化交易",
"name":"cryptocurrency_trade",
"path":"static/html/index.html",
"css_path":"static/css/cryptocurrency_trade.css",
"js_path":"static/js/cryptocurrency_trade.js"
}
},
{
"tag":"global_static",
"global_static": {
"title":"量化交易",
"name":"cryptocurrency_trade",
"css_path":"static/css/ico.css"
}
}
],
"ps": "基于CCXT的数字货币量化交易插件",
"name": "cryptocurrency_trade",
"title": "量化交易",
"versions": ["1.0"],
"tip": "soft",
"checks": "server/cryptocurrency_trade",
"path":"server/cryptocurrency_trade",
"author": "midoks",
"date": "2022-02-25",
"home": "https://github.com/ccxt/ccxt",
"type": "量化交易",
"shell": "install.sh",
"pid": "5",
"sort": 7
}
+63
View File
@@ -0,0 +1,63 @@
#!/bin/bash
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
export PATH
# cd /www/server/mdserver-web/plugins/cryptocurrency_trade && bash install.sh install
curPath=`pwd`
rootPath=$(dirname "$curPath")
rootPath=$(dirname "$rootPath")
serverPath=$(dirname "$rootPath")
VERSION=$2
# pip3 install ccxt
if [ -f ${rootPath}/bin/activate ];then
source ${rootPath}/bin/activate
fi
pip3 install ccxt
pip3 install pandas
pip3 install pandas_ta
pip3 install pyTelegramBotAPI
pip3 install catalyst
pip3 install matplotlib==3.2.2
Install_App()
{
echo '正在安装脚本文件...'
mkdir -p $serverPath/source/cryptocurrency_trade
mkdir -p $serverPath/cryptocurrency_trade
echo "${VERSION}" > $serverPath/cryptocurrency_trade/version.pl
if [ ! -f $serverPath/source/cryptocurrency_trade/ta-lib-0.4.0-src.tar.gz ];then
wget -O $serverPath/source/cryptocurrency_trade/ta-lib-0.4.0-src.tar.gz https://sourceforge.net/projects/ta-lib/files/ta-lib/0.4.0/ta-lib-0.4.0-src.tar.gz
fi
if [ ! -d $serverPath/source/cryptocurrency_trade/ta-lib ];then
cd $serverPath/source/cryptocurrency_trade/ta-lib && tar -xzf ta-lib-0.4.0-src.tar.gz
cd ta-lib && ./configure --prefix=/usr && make && make install
rm -rf $serverPath/source/cryptocurrency_trade/ta-lib
pip3 install ta-lib
fi
cd ${rootPath} && python3 ${rootPath}/plugins/cryptocurrency_trade/index.py start
echo '安装完成'
}
Uninstall_App()
{
rm -rf $serverPath/cryptocurrency_trade
cd ${rootPath} && python3 ${rootPath}/plugins/cryptocurrency_trade/index.py stop
echo "卸载完成"
}
action=$1
if [ "${1}" == 'install' ];then
Install_App
else
Uninstall_App
fi
@@ -0,0 +1,11 @@
.screen-all {
padding: 5px;
}
.s-right .panel-default{
margin-bottom: 10px;
}
.s-left .panel-default{
margin-bottom: 10px;
}
@@ -0,0 +1,11 @@
/* menu start */
.menu .current .menu_plugin_cryptocurrency_trade:hover {
background-image: url("/plugins/file?name=cryptocurrency_trade&f=ico.png");
}
.menu .menu_plugin_cryptocurrency_trade {
background-image: url("/plugins/file?name=cryptocurrency_trade&f=ico.png");
}
/* menu end */
@@ -0,0 +1,65 @@
<div class="main-content">
<div class="screen-all">
<div class="content-screen safe bgw mtb15 ptb10 radius4 row" style="height: 300px;">
<!-- start -->
<div class="s-left col-md-8" style="padding-left: 2.5px;padding-right: 5px; overflow-y: scroll;height: 400px;">
<div class="panel panel-default">
<div class="panel-heading">订单数据</div>
<div class="panel-body">Panel content</div>
</div>
<div class="panel panel-default">
<div class="panel-heading">交易图表</div>
<div class="panel-body" style="padding: 0px;">
<div></div>
<div id="k_echarts" style="width: auto;height:400px;"></div>
</div>
</div>
<div class="panel panel-default">
<div class="panel-heading">策略交易日志</div>
<div class="panel-body" style="padding: 0px;">
<pre id="strategy_log" style="border:none;font-size:12px;white-space: pre;margin: 0px;width: auto;height: 200px;background-color: #333;color:#fff; padding:0 5px">当前没有日志.</pre>
</div>
</div>
</div>
<div class="s-right col-md-4" style="padding-left: 2.5px;padding-right: 5px; overflow-y: scroll;height: 400px;">
<div class="panel panel-default">
<div class="panel-heading">策略配置</div>
<div class="panel-body divtable pd15 relative" style="padding: 2px 2px 5px;">
<table class="table table-hover" width="100%" cellspacing="0" cellpadding="0" border="0">
<thead>
<tr>
<th width="20">序列</th>
<th width="120">说明</th>
<th width="10">状态</th>
<th style="text-align: right;" width="50">操作</th>
</tr>
</thead>
<tbody id="strategy_list"></tbody>
</table>
<div class="dataTables_paginate paging_bootstrap pagination">
<ul id="strategy_list_page" class="page"></ul>
</div>
</div>
</div>
<div class="panel panel-default">
<div class="panel-heading">数据源日志</div>
<div class="panel-body" style="padding: 0px;">
<pre id="datasource_log" style="border:none;font-size:12px;white-space: pre;margin: 0px;width: auto;height: 200px;background-color: #333;color:#fff; padding:0 5px">当前没有日志.</pre>
</div>
</div>
</div>
<!-- end -->
</div>
</div>
</div>
@@ -0,0 +1,964 @@
function appPost(method,args,callback, title){
var _args = null;
if (typeof(args) == 'string'){
_args = JSON.stringify(toArrayObject(args));
} else {
_args = JSON.stringify(args);
}
var _title = '正在获取...';
if (typeof(title) != 'undefined'){
_title = title;
}
var loadT = layer.msg(_title, { icon: 16, time: 0, shade: 0.3 });
$.post('/plugins/run', {name:'cryptocurrency_trade', func:method, args:_args}, function(data) {
layer.close(loadT);
if (!data.status){
layer.msg(data.msg,{icon:0,time:2000,shade: [0.3, '#000']});
return;
}
if(typeof(callback) == 'function'){
callback(data);
}
},'json');
}
function appPostN(method,args,callback, title){
var _args = null;
if (typeof(args) == 'string'){
_args = JSON.stringify(toArrayObject(args));
} else {
_args = JSON.stringify(args);
}
var _title = '正在获取...';
if (typeof(title) != 'undefined'){
_title = title;
}
$.post('/plugins/run', {name:'cryptocurrency_trade', func:method, args:_args}, function(data) {
if(typeof(callback) == 'function'){
callback(data);
}
},'json');
}
function appAsyncPost(method,args){
var _args = null;
if (typeof(args) == 'string'){
_args = JSON.stringify(toArrayObject(args));
} else {
_args = JSON.stringify(args);
}
var loadT = layer.msg('正在获取...', { icon: 16, time: 0, shade: 0.3 });
return syncPost('/plugins/run', {name:'cryptocurrency_trade', func:method, args:_args});
}
function appPostCallbak(method, args,callback, script){
var loadT = layer.msg('正在获取...', { icon: 16, time: 0, shade: 0.3 });
var req_data = {};
req_data['name'] = 'cryptocurrency_trade';
req_data['func'] = method;
if (typeof(script) != 'undefined'){
req_data['script'] = script;
}
if (typeof(args) == 'string'){
req_data['args'] = JSON.stringify(toArrayObject(args));
} else {
req_data['args'] = JSON.stringify(args);
}
$.post('/plugins/callback', req_data, function(data) {
layer.close(loadT);
if (!data.status){
layer.msg(data.msg,{icon:0,time:2000,shade: [0.3, '#000']});
return;
}
if(typeof(callback) == 'function'){
callback(data);
}
},'json');
}
function appPostCallbakNoMsg(method, args,callback, script){
var req_data = {};
req_data['name'] = 'cryptocurrency_trade';
req_data['func'] = method;
if (typeof(script) != 'undefined'){
req_data['script'] = script;
} else {
req_data['script'] = req_data['name'];
}
if (typeof(args) == 'string'){
req_data['args'] = JSON.stringify(toArrayObject(args));
} else {
req_data['args'] = JSON.stringify(args);
}
$.post('/plugins/callback', req_data, function(data) {
if (!data.status){
layer.msg(data.msg,{icon:0,time:2000,shade: [0.3, '#000']});
return;
}
if(typeof(callback) == 'function'){
callback(data);
}
},'json');
}
function dbConf(){
appPost('get_db_conf','',function(data){
var rdata = $.parseJSON(data.data);
// console.log(rdata);
var db_host = '127.0.0.1';
var db_port = '3306';
var db_name = 'cryptocurrency_trade';
var db_user = 'cryptocurrency_trade';
var db_pass = 'cryptocurrency_trade';
if(rdata['status']){
db_data = rdata['data'];
db_host = db_data['db_host'];
db_port = db_data['db_port'];
db_name = db_data['db_name'];
db_user = db_data['db_user'];
db_pass = db_data['db_pass'];
}
var mlist = '';
mlist += '<p><span>数据库地址</span><input style="width: 250px;" class="bt-input-text mr5" name="db_host" value="'+db_host+'" type="text"></p>'
mlist += '<p><span>数据库端口</span><input style="width: 250px;" class="bt-input-text mr5" name="db_port" value="'+db_port+'" type="text"></p>'
mlist += '<p><span>数据库名称</span><input style="width: 250px;" class="bt-input-text mr5" name="db_name" value="'+db_name+'" type="text"></p>'
mlist += '<p><span>用户名</span><input style="width: 250px;" class="bt-input-text mr5" name="db_user" value="'+db_user+'" type="text"></p>'
mlist += '<p><span>密码</span><input style="width: 250px;" class="bt-input-text mr5" name="db_pass" value="'+db_pass+'" type="text"></p>'
var option = '<style>.conf_p p{margin-bottom: 2px}</style>\
<div class="conf_p" style="margin-bottom:0">\
' + mlist + '\
<div style="margin-top:10px; padding-right:15px" class="text-right">\
<button class="btn btn-success btn-sm" onclick="submitDbConf()">保存</button>\
</div>\
</div>';
$(".soft-man-con").html(option);
});
}
function submitDbConf(){
var pull_data = {};
pull_data['db_host'] = $('input[name="db_host"]').val();
pull_data['db_port'] = $('input[name="db_port"]').val();
pull_data['db_name'] = $('input[name="db_name"]').val();
pull_data['db_user'] = $('input[name="db_user"]').val();
pull_data['db_pass'] = $('input[name="db_pass"]').val();
appPost('set_db_conf',pull_data,function(data){
var rdata = $.parseJSON(data.data);
layer.msg(rdata['msg'],{icon:rdata['status']?1:2,time:2000,shade: [0.3, '#000']});
});
}
function userConf(){
appPost('get_user_conf','',function(data){
var rdata = $.parseJSON(data.data);
var app_key = 'app_key';
var secret = 'secret';
var password = 'password';
var uid = 'uid';
var exchange = 'okex';
if(rdata['status']){
db_data = rdata['data'];
app_key = db_data['app_key'];
secret = db_data['secret'];
password = db_data['password'];
uid = db_data['uid'];
exchange = db_data['exchange'];;
}
var mlist = '';
mlist += '<p><span>交易所</span><input style="width: 250px;" class="bt-input-text mr5" name="exchange" value="'+exchange+'" type="text"><font>必填写[okex, binance]</font></p>'
mlist += '<p><span>apiKey</span><input style="width: 250px;" class="bt-input-text mr5" name="app_key" value="'+app_key+'" type="text"><font>必填写</font></p>'
mlist += '<p><span>secret</span><input style="width: 250px;" class="bt-input-text mr5" name="secret" value="'+secret+'" type="text"><font>必填写</font></p>'
mlist += '<p><span>password</span><input style="width: 250px;" class="bt-input-text mr5" name="password" value="'+password+'" type="text"><font>根据情况填写</font></p>'
mlist += '<p><span>uid</span><input style="width: 250px;" class="bt-input-text mr5" name="uid" value="'+uid+'" type="text"><font>根据情况填写</font></p>'
var option = '<style>.conf_p p{margin-bottom: 2px}</style>\
<div class="conf_p" style="margin-bottom:0">\
' + mlist + '\
<div style="margin-top:10px; padding-right:15px" class="text-right">\
<button class="btn btn-success btn-sm" onclick="submitUserConf()">保存</button>\
</div>\
</div>';
$(".soft-man-con").html(option);
});
}
function submitUserConf(){
var pull_data = {};
pull_data['app_key'] = $('input[name="app_key"]').val();
pull_data['secret'] = $('input[name="secret"]').val();
pull_data['password'] = $('input[name="password"]').val();
pull_data['uid'] = $('input[name="uid"]').val();
pull_data['exchange'] = $('input[name="exchange"]').val();
appPost('set_user_conf',pull_data,function(data){
var rdata = $.parseJSON(data.data);
layer.msg(rdata['msg'],{icon:rdata['status']?1:2,time:2000,shade: [0.3, '#000']});
});
}
function syncDataList(){
appPost('sync_data_list', {}, function(data){
var rdata = $.parseJSON(data.data);
var list = '';
if (rdata['status']){
var dlist = rdata['data']['list'];
for(i in dlist){
list += '<tr>';
list += '<td>' + dlist[i] +'</td>';
list += '<td style="text-align:right">' +
'<a href="javascript:;" class="btlink" onclick="syncDataDelete(\''+dlist[i]+'\')" title="删除">删除</a>' +
'</td>';
list += '</tr>';
}
}
if( list == '' ){
list = "<tr><td colspan='2'>当前没有数据</td></tr>";
}
var task_status = rdata['data']['task_status'];
var task_status_check = '';
if (task_status){
task_status_check = 'checked';
}
var con = '<div class="safe bgw">\
<div>\
<button onclick="syncDataAdd()" title="添加币种" class="btn btn-success btn-sm" type="button" style="margin-right: 5px;">添加币种</button>\
<div class="ss-text pull-left mr50">\
<em>是否启动</em>\
<div class="ssh-item">\
<input class="btswitch btswitch-ios" id="add_task" type="checkbox" '+task_status_check+'>\
<label class="btswitch-btn" for="add_task" onclick="syncDataAddTask()"></label>\
</div>\
</div>\
</div>\
<div class="divtable mtb10">\
<div class="tablescroll">\
<table id="DataBody" class="table table-hover" width="100%" cellspacing="0" cellpadding="0" border="0" style="border: 0 none;">\
<thead>\
<th>名称</th>\
<th style="text-align:right;">操作</th></tr>\
</thead>\
<tbody>'+ list +'</tbody>\
</table>\
</div>\
</div>\
</div>';
con += '<div class="code">\
<span>详细如下:</span>\
<span>*:添加同步的币种,都小写,以USDT为本币同步数据。</span>\
<span>*:需要提前安装supervisor插件。</span>\
</div>'
$(".soft-man-con").html(con);
$('#databasePage').html(rdata.page);
});
}
function syncDataAddTask(){
var at_check = $('#add_task').prop('checked');
appPost("sync_data_add_task", {'check':at_check?'0':'1'}, function(data){
rdata = $.parseJSON(data.data);
showMsg(rdata.msg,function(){
if (rdata.status){
syncDataList();
}
},{icon:rdata.status?1:2});
});
}
function syncDataDelete(name){
appPost("sync_data_delete", {"token":name}, function(data){
rdata = $.parseJSON(data.data);
showMsg(rdata.msg,function(){
if (rdata.status){
syncDataList();
}
},{icon:rdata.status?1:2});
});
}
function syncDataAdd() {
layer.open({
type: 1,
area: '500px',
title: '添加同步数据',
closeBtn: 2,
shift: 0,
shadeClose: false,
btn: ['确定', '取消'],
content: "<div class='bt_conter bt-form pd15' style='height:auto;width:100%;'>\
<div class='line'>\
<span class='tname'>名称</span>\
<div class='info-r c4'>\
<input id='name' class='bt-input-text' type='text' name='name' placeholder='请输入名称' style='width:270px' />\
</div>\
</div>\
<ul class='help-info-text c7' style='padding-left: 29px;margin-top:5px;'>\
<li style='color:#F00'>注意:币种名称用小写!</li>\
</ul>\
</div>",
yes: function(index, layero){
var token = $('input[name="name"]').val();
appPost("sync_data_add", {"token":token}, function(data){
rdata = $.parseJSON(data.data);
showMsg(rdata.msg,function(){
if (rdata.status){
layer.close(index);
syncDataList();
}
},{icon:rdata.status?1:2});
})
return;
}
});
}
function onlineEditStrategyFile(k, f, tag) {
if(k != 0) {
var l = $("#PathPlace input").val();
var h = $("#textBody").val();
var a = $("select[name=encoding]").val();
var loadT = layer.msg("正在保存中...", {icon: 16,time: 0});
appPostCallbakNoMsg('save_body',{'data':h,'path':f,'encoding':a,"tag":tag}, function(data){
var rdata = data.data;
showMsg(rdata.msg, function(){
if (rdata.status){
layer.close(loadT);
}
},{icon: rdata.status ? 1 : 2});
});
return
}
var e = layer.msg("正在读取文件,请稍候...", {icon: 16,time: 0});
var g = f.split(".");
var b = g[g.length - 1];
var d;
switch(b) {
case "html":
var j = {
name: "htmlmixed",
scriptTypes: [{
matches: /\/x-handlebars-template|\/x-mustache/i,
mode: null
}, {
matches: /(text|application)\/(x-)?vb(a|script)/i,
mode: "vbscript"
}]
};
d = j;
break;
case "htm":
var j = {
name: "htmlmixed",
scriptTypes: [{
matches: /\/x-handlebars-template|\/x-mustache/i,
mode: null
}, {
matches: /(text|application)\/(x-)?vb(a|script)/i,
mode: "vbscript"
}]
};
d = j;
break;
case "js":
d = "text/javascript";
break;
case "json":
d = "application/ld+json";
break;
case "css":
d = "text/css";
break;
case "php":
d = "application/x-httpd-php";
break;
case "tpl":
d = "application/x-httpd-php";
break;
case "xml":
d = "application/xml";
break;
case "sql":
d = "text/x-sql";
break;
case "conf":
d = "text/x-nginx-conf";
break;
default:
var j = {
name: "htmlmixed",
scriptTypes: [{
matches: /\/x-handlebars-template|\/x-mustache/i,
mode: null
}, {
matches: /(text|application)\/(x-)?vb(a|script)/i,
mode: "vbscript"
}]
};
d = j
}
$.post("/files/get_body", "path=" + encodeURIComponent(f), function(s) {
if(s.status === false){
layer.msg(s.msg,{icon:5});
return;
}
layer.close(e);
var u = ["utf-8", "GBK", "GB2312", "BIG5"];
var n = "";
var m = "";
var o = "";
for(var p = 0; p < u.length; p++) {
m = s.data.encoding == u[p] ? "selected" : "";
n += '<option value="' + u[p] + '" ' + m + ">" + u[p] + "</option>";
}
var code_mirror = null;
var r = layer.open({
type: 1,
shift: 5,
closeBtn: 1,
area: ["90%", "90%"],
title: "在线编辑[" + f + "]",
btn:['保存','关闭'],
content: '<form class="bt-form pd20">\
<div class="line">\
<p style="color:red;margin-bottom:10px">提示:Ctrl+F 搜索关键字,Ctrl+G 查找下一个,Ctrl+S 保存,Ctrl+Shift+R 查找替换!\
<select class="bt-input-text" name="encoding" style="width: 74px;position: absolute;top: 31px;right: 19px;height: 22px;z-index: 9999;border-radius: 0;">' + n + '</select>\
</p>\
<textarea class="mCustomScrollbar bt-input-text" id="textBody" style="width:100%;margin:0 auto;line-height: 1.8;position: relative;top: 10px;" value="" />\
</div>\
</form>',
success:function(){
$("#textBody").text(s.data.data);
var q = $(window).height() * 0.9;
$("#textBody").height(q - 160);
code_mirror = CodeMirror.fromTextArea(document.getElementById("textBody"), {
extraKeys: {
"Ctrl-F": "findPersistent",
"Ctrl-H": "replaceAll",
"Ctrl-S": function() {
$("#textBody").text(code_mirror.getValue());
onlineEditStrategyFile(2, f,tag);
},
"Cmd-S":function() {
$("#textBody").text(code_mirror.getValue());
onlineEditStrategyFile(2, f,tag);
},
},
mode: d,
lineNumbers: true,
matchBrackets: true,
matchtags: true,
autoMatchParens: true
});
code_mirror.focus();
code_mirror.setSize("auto", q - 150);
$(window).resize(function(){
var q = $(window).height() * 0.9;
code_mirror.setSize("auto", q - 150);
});
},
yes:function(){
$("#textBody").text(code_mirror.getValue());
onlineEditStrategyFile(1, f, tag);
}
});
//////////////////
},'json');
}
// ------------------------------------------------------------------------------
// ------------------------------------------------------------------------------
// 大屏页功能 --------------------------------------------------------------------
// ------------------------------------------------------------------------------
// ------------------------------------------------------------------------------
function changeDivH(){
var l = $(window).height();
$('.content-screen').css('height',l-80);
$('.s-right').css('height',l-80-10);
$('.s-left').css('height',l-80-10);
}
function dataSourceLog(){
appPostCallbakNoMsg('get_datasource_logs',{}, function(rdata){
$('#datasource_log').html(rdata.data);
});
}
function dataStrategyLog(){
appPostCallbakNoMsg('get_strategy_logs',{}, function(rdata){
$('#strategy_log').html(rdata.data);
});
}
// $('#strategy_list').find('span[data-id="01"]')
function setStrategyStatus(id,status){
appPostCallbakNoMsg('set_strategy_status',{"id":id,"status":status}, function(data){
var rdata = data.data;
showMsg(rdata.msg,function(){
if (rdata.status){
if (status == 'start'){
$('#strategy_list').find('tr[data-id="'+id+'"] td span').removeClass('glyphicon-pause').addClass('glyphicon-play').css('color','#20a53a');
} else{
$('#strategy_list').find('tr[data-id="'+id+'"] td span').removeClass('glyphicon-play').addClass('glyphicon-pause').css('color','red');
}
}
},{icon:rdata.status?1:2},2000);
});
}
function setStrategyRestart(id){
appPostCallbakNoMsg('set_strategy_restart',{"id":id}, function(data){
console.log(data);
var rdata = data.data;
showMsg(rdata.msg,function(){
if (rdata.status){
}
},{icon:rdata.status?1:2},2000);
});
}
function setStrategyEdit(id){
appPostCallbakNoMsg('get_strategy_path',{"id":id}, function(data){
onlineEditStrategyFile(0,data.data.msg,id);
});
}
function getStrategyList(p=1){
appPostCallbakNoMsg('get_strategy_list',{'page':p}, function(rdata){
// console.log(rdata);
ldata = rdata.data.data;
var tBody = '';
for (var i = 0; i < ldata.length; i++) {
tBody += '<tr data-id="'+ldata[i]['id']+'">'
tBody += '<td>'+ldata[i]['id']+'</td>';
tBody += '<td>'+ldata[i]['name']+'</td>';
if (ldata[i]['status'] == 'start'){
tBody += '<td><span style="color:#20a53a;cursor: pointer;" class="strategy_status glyphicon glyphicon-play"></span></td>';
} else{
tBody += '<td><span style="color:red;cursor: pointer;" class="strategy_status glyphicon glyphicon-pause"></span></td>';
}
tBody += "<td style='text-align: right;'><a class='btlink restart'>重启</a> | <a class='btlink edit'>编辑</a></td>";
tBody +='<tr>';
}
// console.log(tBody);
$('#strategy_list').html(tBody);
$('#strategy_list_page').html(rdata.data.list);
$('#strategy_list .strategy_status').click(function(){
var id = $(this).parent().parent().data('id');
var status = 'stop';
if ($(this).hasClass('glyphicon-pause')){
status = 'start';
}
setStrategyStatus(id,status);
});
$('#strategy_list .restart').click(function(){
var id = $(this).parent().parent().data('id');
setStrategyRestart(id);
});
$('#strategy_list .edit').click(function(){
var id = $(this).parent().parent().data('id');
setStrategyEdit(id);
});
});
}
function calcKLineChats(){
var chartDom = document.getElementById('k_echarts');
var myChart = echarts.init(chartDom);
var option;
const upColor = '#ec0000';
const upBorderColor = '#8A0000';
const downColor = '#00da3c';
const downBorderColor = '#008F28';
// Each item: open,close,lowest,highest
const data0 = splitData([
['2013/1/24', 2320.26, 2320.26, 2287.3, 2362.94],
['2013/1/25', 2300, 2291.3, 2288.26, 2308.38],
['2013/1/28', 2295.35, 2346.5, 2295.35, 2346.92],
['2013/1/29', 2347.22, 2358.98, 2337.35, 2363.8],
['2013/1/30', 2360.75, 2382.48, 2347.89, 2383.76],
['2013/1/31', 2383.43, 2385.42, 2371.23, 2391.82],
['2013/2/1', 2377.41, 2419.02, 2369.57, 2421.15],
['2013/2/4', 2425.92, 2428.15, 2417.58, 2440.38],
['2013/2/5', 2411, 2433.13, 2403.3, 2437.42],
['2013/2/6', 2432.68, 2434.48, 2427.7, 2441.73],
['2013/2/7', 2430.69, 2418.53, 2394.22, 2433.89],
['2013/2/8', 2416.62, 2432.4, 2414.4, 2443.03],
['2013/2/18', 2441.91, 2421.56, 2415.43, 2444.8],
['2013/2/19', 2420.26, 2382.91, 2373.53, 2427.07],
['2013/2/20', 2383.49, 2397.18, 2370.61, 2397.94],
['2013/2/21', 2378.82, 2325.95, 2309.17, 2378.82],
['2013/2/22', 2322.94, 2314.16, 2308.76, 2330.88],
['2013/2/25', 2320.62, 2325.82, 2315.01, 2338.78],
['2013/2/26', 2313.74, 2293.34, 2289.89, 2340.71],
['2013/2/27', 2297.77, 2313.22, 2292.03, 2324.63],
['2013/2/28', 2322.32, 2365.59, 2308.92, 2366.16],
['2013/3/1', 2364.54, 2359.51, 2330.86, 2369.65],
['2013/3/4', 2332.08, 2273.4, 2259.25, 2333.54],
['2013/3/5', 2274.81, 2326.31, 2270.1, 2328.14],
['2013/3/6', 2333.61, 2347.18, 2321.6, 2351.44],
['2013/3/7', 2340.44, 2324.29, 2304.27, 2352.02],
['2013/3/8', 2326.42, 2318.61, 2314.59, 2333.67],
['2013/3/11', 2314.68, 2310.59, 2296.58, 2320.96],
['2013/3/12', 2309.16, 2286.6, 2264.83, 2333.29],
['2013/3/13', 2282.17, 2263.97, 2253.25, 2286.33],
['2013/3/14', 2255.77, 2270.28, 2253.31, 2276.22],
['2013/3/15', 2269.31, 2278.4, 2250, 2312.08],
['2013/3/18', 2267.29, 2240.02, 2239.21, 2276.05],
['2013/3/19', 2244.26, 2257.43, 2232.02, 2261.31],
['2013/3/20', 2257.74, 2317.37, 2257.42, 2317.86],
['2013/3/21', 2318.21, 2324.24, 2311.6, 2330.81],
['2013/3/22', 2321.4, 2328.28, 2314.97, 2332],
['2013/3/25', 2334.74, 2326.72, 2319.91, 2344.89],
['2013/3/26', 2318.58, 2297.67, 2281.12, 2319.99],
['2013/3/27', 2299.38, 2301.26, 2289, 2323.48],
['2013/3/28', 2273.55, 2236.3, 2232.91, 2273.55],
['2013/3/29', 2238.49, 2236.62, 2228.81, 2246.87],
['2013/4/1', 2229.46, 2234.4, 2227.31, 2243.95],
['2013/4/2', 2234.9, 2227.74, 2220.44, 2253.42],
['2013/4/3', 2232.69, 2225.29, 2217.25, 2241.34],
['2013/4/8', 2196.24, 2211.59, 2180.67, 2212.59],
['2013/4/9', 2215.47, 2225.77, 2215.47, 2234.73],
['2013/4/10', 2224.93, 2226.13, 2212.56, 2233.04],
['2013/4/11', 2236.98, 2219.55, 2217.26, 2242.48],
['2013/4/12', 2218.09, 2206.78, 2204.44, 2226.26],
['2013/4/15', 2199.91, 2181.94, 2177.39, 2204.99],
['2013/4/16', 2169.63, 2194.85, 2165.78, 2196.43],
['2013/4/17', 2195.03, 2193.8, 2178.47, 2197.51],
['2013/4/18', 2181.82, 2197.6, 2175.44, 2206.03],
['2013/4/19', 2201.12, 2244.64, 2200.58, 2250.11],
['2013/4/22', 2236.4, 2242.17, 2232.26, 2245.12],
['2013/4/23', 2242.62, 2184.54, 2182.81, 2242.62],
['2013/4/24', 2187.35, 2218.32, 2184.11, 2226.12],
['2013/4/25', 2213.19, 2199.31, 2191.85, 2224.63],
['2013/4/26', 2203.89, 2177.91, 2173.86, 2210.58],
['2013/5/2', 2170.78, 2174.12, 2161.14, 2179.65],
['2013/5/3', 2179.05, 2205.5, 2179.05, 2222.81],
['2013/5/6', 2212.5, 2231.17, 2212.5, 2236.07],
['2013/5/7', 2227.86, 2235.57, 2219.44, 2240.26],
['2013/5/8', 2242.39, 2246.3, 2235.42, 2255.21],
['2013/5/9', 2246.96, 2232.97, 2221.38, 2247.86],
['2013/5/10', 2228.82, 2246.83, 2225.81, 2247.67],
['2013/5/13', 2247.68, 2241.92, 2231.36, 2250.85],
['2013/5/14', 2238.9, 2217.01, 2205.87, 2239.93],
['2013/5/15', 2217.09, 2224.8, 2213.58, 2225.19],
['2013/5/16', 2221.34, 2251.81, 2210.77, 2252.87],
['2013/5/17', 2249.81, 2282.87, 2248.41, 2288.09],
['2013/5/20', 2286.33, 2299.99, 2281.9, 2309.39],
['2013/5/21', 2297.11, 2305.11, 2290.12, 2305.3],
['2013/5/22', 2303.75, 2302.4, 2292.43, 2314.18],
['2013/5/23', 2293.81, 2275.67, 2274.1, 2304.95],
['2013/5/24', 2281.45, 2288.53, 2270.25, 2292.59],
['2013/5/27', 2286.66, 2293.08, 2283.94, 2301.7],
['2013/5/28', 2293.4, 2321.32, 2281.47, 2322.1],
['2013/5/29', 2323.54, 2324.02, 2321.17, 2334.33],
['2013/5/30', 2316.25, 2317.75, 2310.49, 2325.72],
['2013/5/31', 2320.74, 2300.59, 2299.37, 2325.53],
['2013/6/3', 2300.21, 2299.25, 2294.11, 2313.43],
['2013/6/4', 2297.1, 2272.42, 2264.76, 2297.1],
['2013/6/5', 2270.71, 2270.93, 2260.87, 2276.86],
['2013/6/6', 2264.43, 2242.11, 2240.07, 2266.69],
['2013/6/7', 2242.26, 2210.9, 2205.07, 2250.63],
['2013/6/13', 2190.1, 2148.35, 2126.22, 2190.1]
]);
function splitData(rawData) {
const categoryData = [];
const values = [];
for (var i = 0; i < rawData.length; i++) {
categoryData.push(rawData[i].splice(0, 1)[0]);
values.push(rawData[i]);
}
return {
categoryData: categoryData,
values: values
};
}
function calculateMA(dayCount) {
var result = [];
for (var i = 0, len = data0.values.length; i < len; i++) {
if (i < dayCount) {
result.push('-');
continue;
}
var sum = 0;
for (var j = 0; j < dayCount; j++) {
sum += +data0.values[i - j][1];
}
result.push(sum / dayCount);
}
return result;
}
option = {
title: {
text: '上证指数',
left: 0
},
tooltip: {
trigger: 'axis',
axisPointer: {
type: 'cross'
}
},
legend: {
data: ['日K', 'MA5', 'MA10', 'MA20', 'MA30']
},
grid: {
left: '10%',
right: '10%',
bottom: '15%'
},
xAxis: {
type: 'category',
data: data0.categoryData,
boundaryGap: false,
axisLine: { onZero: false },
splitLine: { show: false },
min: 'dataMin',
max: 'dataMax'
},
yAxis: {
scale: true,
splitArea: {
show: true
}
},
dataZoom: [
{
type: 'inside',
start: 50,
end: 100
},
{
show: true,
type: 'slider',
top: '90%',
start: 50,
end: 100
}
],
series: [
{
name: '日K',
type: 'candlestick',
data: data0.values,
itemStyle: {
color: upColor,
color0: downColor,
borderColor: upBorderColor,
borderColor0: downBorderColor
},
markPoint: {
label: {
formatter: function (param) {
return param != null ? Math.round(param.value) + '' : '';
}
},
data: [
{
name: 'Mark',
coord: ['2013/5/31', 2300],
value: 2300,
itemStyle: {
color: 'rgb(41,60,85)'
}
},
{
name: 'highest value',
type: 'max',
valueDim: 'highest'
},
{
name: 'lowest value',
type: 'min',
valueDim: 'lowest'
},
{
name: 'average value on close',
type: 'average',
valueDim: 'close'
}
],
tooltip: {
formatter: function (param) {
return param.name + '<br>' + (param.data.coord || '');
}
}
},
markLine: {
symbol: ['none', 'none'],
data: [
[
{
name: 'from lowest to highest',
type: 'min',
valueDim: 'lowest',
symbol: 'circle',
symbolSize: 10,
label: {
show: false
},
emphasis: {
label: {
show: false
}
}
},
{
type: 'max',
valueDim: 'highest',
symbol: 'circle',
symbolSize: 10,
label: {
show: false
},
emphasis: {
label: {
show: false
}
}
}
],
{
name: 'min line on close',
type: 'min',
valueDim: 'close'
},
{
name: 'max line on close',
type: 'max',
valueDim: 'close'
}
]
}
},
{
name: 'MA5',
type: 'line',
data: calculateMA(5),
smooth: true,
lineStyle: {
opacity: 0.5
}
},
{
name: 'MA10',
type: 'line',
data: calculateMA(10),
smooth: true,
lineStyle: {
opacity: 0.5
}
},
{
name: 'MA20',
type: 'line',
data: calculateMA(20),
smooth: true,
lineStyle: {
opacity: 0.5
}
},
{
name: 'MA30',
type: 'line',
data: calculateMA(30),
smooth: true,
lineStyle: {
opacity: 0.5
}
}
]
};
option && myChart.setOption(option);
}
$(document).ready(function(){
var tag = $.getUrlParam('tag');
if(tag == 'cryptocurrency_trade'){
changeDivH();
// 获取数据源更新日志
dataSourceLog();
setInterval(function(){
dataSourceLog();
},3000);
// 获取策略更新日志
dataStrategyLog();
setInterval(function(){
dataStrategyLog();
},5000);
getStrategyList(1);
calcKLineChats();
}
});
$(window).resize(function(){
changeDivH();
});
+19 -1
View File
@@ -23,6 +23,8 @@ def singleton(cls):
@singleton
class nosqlMySQL():
__sid = None
__DB_PASS = None
__DB_USER = None
__DB_PORT = 3306
@@ -37,9 +39,19 @@ class nosqlMySQL():
pass
def setSid(self, sid):
self.__sid = sid
self.__config = self.get_options(sid=sid)
def conn(self):
if self.__sid is None:
return False
if self.__sid is not None:
mycnf_path = "{}/{}/etc/my.cnf".format(mw.getServerDir(),self.__sid)
if not os.path.exists(mycnf_path):
return False
self.__DB_PORT = int(self.__config['port'])
self.__DB_USER = self.__config['username']
self.__DB_PASS = self.__config['password']
@@ -72,8 +84,10 @@ class nosqlMySQL():
result['host'] = '127.0.0.1'
result['username'] = 'root'
if sid in ['mysql', 'mysql-apt', 'mysql-yum']:
if sid in ['mysql', 'mysql-apt', 'mysql-yum', 'mysql-community']:
my_cnf_path = "{}/{}/etc/my.cnf".format(mw.getServerDir(),sid)
if not os.path.exists(my_cnf_path):
return False
mydb_content = mw.readFile(my_cnf_path)
if not mydb_content: return False
@@ -118,6 +132,10 @@ class nosqlMySQL():
local_mysql_yum = "{}/mysql-yum/etc/my.cnf".format(mw.getServerDir())
if os.path.exists(local_mysql_yum):
data.append({'name':'本地服务器[yum]', 'val':'mysql-yum'})
local_mysql_yum = "{}/mysql-community/etc/my.cnf".format(mw.getServerDir())
if os.path.exists(local_mysql_yum):
data.append({'name':'本地服务器[Tar]', 'val':'mysql-community'})
return mw.returnData(True, 'ok', data)
@singleton
+1 -1
View File
@@ -1,5 +1,5 @@
{
"sort": 7,
"sort": 1000,
"ps": "Docker是一个开源的应用容器引擎",
"name": "docker",
"title": "Docker",
+3
View File
@@ -51,6 +51,9 @@ Install_App()
fi
# FlameGraph end
# apt install linux-tools-$(uname -r) linux-tools-generic -y
# apt install linux-tools-$(uname -r) linux-tools-generic -y --fix-missing
shell_file=${curPath}/versions/${OSNAME}.sh
+21
View File
@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2024 mw-plugin
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
+8
View File
@@ -0,0 +1,8 @@
# dztasks
任务调度
### 安装
```
rm -rf /www/server/mdserver-web/plugins/dztasks && cd /www/server/mdserver-web/plugins && rm -rf dztasks && git clone https://github.com/mw-plugin/dztasks && cd dztasks && rm -rf .git && cd /www/server/mdserver-web/plugins/dztasks && bash install.sh install 1.1
```
+19
View File
@@ -0,0 +1,19 @@
app_name = dztasks
run_mode = prod
[web]
http_port = 11011
[session]
provider = file
[admin]
user = {$ADMIN_NAME}
pass = {$ADMIN_PASS}
[plugins]
path = {$SERVER_APP}/plugins
[security]
install_lock = true
secret_key = VQOXEKGNIAIDXQI
Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

+32
View File
@@ -0,0 +1,32 @@
<style>
.overflow_hide {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
vertical-align: middle;
}
</style>
<div class="bt-form">
<div class='plugin_version'></div>
<div class="bt-w-main">
<div class="bt-w-menu">
<p class="bgw" onclick="pluginService('dztasks');">服务</p>
<p onclick="pluginInitD('dztasks');">自启动</p>
<p onclick="dzCommonFunc();">常用功能</p>
<p onclick="pluginConfigTpl('dztasks',$('.plugin_version').attr('version'));">配置修改</p>
<p onclick="pluginLogs('dztasks','','run_log');">运行日志</p>
<p onclick="zdReadme();">相关说明</p>
</div>
<div class="bt-w-con pd15">
<div class="soft-man-con" style="height: 520px; overflow: auto;"></div>
</div>
</div>
</div>
<script type="text/javascript">
resetPluginWinHeight(600);
$.getScript( "/plugins/file?name=dztasks&f=js/dztasks.js", function(){
pluginService('dztasks', $('.plugin_version').attr('version'));
});
</script>
+318
View File
@@ -0,0 +1,318 @@
# coding:utf-8
import sys
import io
import os
import time
import re
web_dir = os.getcwd() + "/web"
if os.path.exists(web_dir):
sys.path.append(web_dir)
os.chdir(web_dir)
import core.mw as mw
app_debug = False
if mw.isAppleSystem():
app_debug = True
def getPluginName():
return 'dztasks'
def getPluginDir():
return mw.getPluginDir() + '/' + getPluginName()
def getServerDir():
return mw.getServerDir() + '/' + getPluginName()
def getInitDFile():
current_os = mw.getOs()
if current_os == 'darwin':
return '/tmp/' + getPluginName()
if current_os.startswith('freebsd'):
return '/etc/rc.d/' + getPluginName()
return '/etc/init.d/' + getPluginName()
def getConf():
path = getServerDir() + "/custom/conf/app.conf"
return path
def getConfTpl():
path = getPluginDir() + "/config/dztasks.conf"
return path
def getInitDTpl():
path = getPluginDir() + "/init.d/" + getPluginName() + ".tpl"
return path
def getArgs():
args = sys.argv[3:]
tmp = {}
args_len = len(args)
if args_len == 1:
t = args[0].strip('{').strip('}')
if t.strip() == '':
tmp = []
else:
t = t.split(':')
tmp[t[0]] = t[1]
tmp[t[0]] = t[1]
elif args_len > 1:
for i in range(len(args)):
t = args[i].split(':')
tmp[t[0]] = t[1]
return tmp
def checkArgs(data, ck=[]):
for i in range(len(ck)):
if not ck[i] in data:
return (False, mw.returnJson(False, '参数:(' + ck[i] + ')没有!'))
return (True, mw.returnJson(True, 'ok'))
def configTpl():
# path = getPluginDir() + '/tpl'
# pathFile = os.listdir(path)
tmp = []
return mw.getJson(tmp)
def readConfigTpl():
args = getArgs()
data = checkArgs(args, ['file'])
if not data[0]:
return data[1]
content = mw.readFile(args['file'])
content = contentReplace(content)
return mw.returnJson(True, 'ok', content)
def getPidFile():
file = getConf()
content = mw.readFile(file)
rep = r'pidfile\s*(.*)'
tmp = re.search(rep, content)
return tmp.groups()[0].strip()
def status():
cmd = "ps aux|grep dztasks|grep -v grep|grep -v python|grep -v mdserver-web|awk '{print $2}'"
data = mw.execShell(cmd)
if data[0] == '':
return 'stop'
return 'start'
def contentReplace(content):
service_path = mw.getServerDir()
content = content.replace('{$ROOT_PATH}', mw.getFatherDir())
content = content.replace('{$SERVER_PATH}', service_path)
content = content.replace('{$SERVER_APP}', service_path + '/dztasks')
content = content.replace('{$ADMIN_NAME}', mw.getRandomString(6))
content = content.replace('{$ADMIN_PASS}', mw.getRandomString(10))
return content
def initDreplace():
file_tpl = getInitDTpl()
service_path = mw.getServerDir()
initD_path = getServerDir() + '/init.d'
if not os.path.exists(initD_path):
os.mkdir(initD_path)
file_bin = initD_path + '/' + getPluginName()
# initd replace
if not os.path.exists(file_bin):
content = mw.readFile(file_tpl)
content = contentReplace(content)
mw.writeFile(file_bin, content)
mw.execShell('chmod +x ' + file_bin)
# log
dataLog = getServerDir() + '/data'
if not os.path.exists(dataLog):
mw.execShell('chmod +x ' + file_bin)
app_dir = getServerDir() + '/custom/conf'
if not os.path.exists(app_dir):
mw.execShell('mkdir -p ' + app_dir)
# config replace
dst_conf = getServerDir() + '/custom/conf/app.conf'
dst_conf_init = getServerDir() + '/init.pl'
if not os.path.exists(dst_conf_init):
content = mw.readFile(getConfTpl())
# print(content)
content = contentReplace(content)
mw.writeFile(dst_conf, content)
mw.writeFile(dst_conf_init, 'ok')
# systemd
systemDir = mw.systemdCfgDir()
systemService = systemDir + '/' + getPluginName() + '.service'
if os.path.exists(systemDir) and not os.path.exists(systemService):
systemServiceTpl = getPluginDir() + '/init.d/' + getPluginName() + '.service.tpl'
content = mw.readFile(systemServiceTpl)
content = contentReplace(content)
mw.writeFile(systemService, content)
mw.execShell('systemctl daemon-reload')
return file_bin
def dzOp(method):
file = initDreplace()
current_os = mw.getOs()
if current_os == "darwin":
data = mw.execShell(file + ' ' + method)
if data[1] == '':
return 'ok'
return data[1]
if current_os.startswith("freebsd"):
data = mw.execShell('service ' + getPluginName() + ' ' + method)
if data[1] == '':
return 'ok'
return data[1]
data = mw.execShell('systemctl ' + method + ' ' + getPluginName())
if data[1] == '':
return 'ok'
return data[1]
def start():
return dzOp('start')
def stop():
return dzOp('stop')
def restart():
status = dzOp('restart')
log_file = runLog()
mw.execShell("echo '' > " + log_file)
return status
def reload():
return dzOp('reload')
def initdStatus():
current_os = mw.getOs()
if current_os == 'darwin':
return "Apple Computer does not support"
if current_os.startswith('freebsd'):
initd_bin = getInitDFile()
if os.path.exists(initd_bin):
return 'ok'
shell_cmd = 'systemctl status ' + \
getPluginName() + ' | grep loaded | grep "enabled;"'
data = mw.execShell(shell_cmd)
if data[0] == '':
return 'fail'
return 'ok'
def initdInstall():
current_os = mw.getOs()
if current_os == 'darwin':
return "Apple Computer does not support"
# freebsd initd install
if current_os.startswith('freebsd'):
import shutil
source_bin = initDreplace()
initd_bin = getInitDFile()
shutil.copyfile(source_bin, initd_bin)
mw.execShell('chmod +x ' + initd_bin)
mw.execShell('sysrc ' + getPluginName() + '_enable="YES"')
return 'ok'
mw.execShell('systemctl enable ' + getPluginName())
return 'ok'
def initdUinstall():
current_os = mw.getOs()
if current_os == 'darwin':
return "Apple Computer does not support"
if current_os.startswith('freebsd'):
initd_bin = getInitDFile()
os.remove(initd_bin)
mw.execShell('sysrc ' + getPluginName() + '_enable="NO"')
return 'ok'
mw.execShell('systemctl disable ' + getPluginName())
return 'ok'
def runLog():
return getServerDir() + '/logs.pl'
def getDzPort():
file = getConf()
content = mw.readFile(file)
rep = r'port\s*=\s*(.*)'
tmp = re.search(rep, content)
return tmp.groups()[0].strip()
def homePage():
http_port = getDzPort()
ip = mw.getLocalIp()
if mw.isAppleSystem():
ip = '127.0.0.1'
url = 'http://'+ip+":"+str(http_port)
# print(url)
return mw.returnJson(True, 'ok!', url)
if __name__ == "__main__":
func = sys.argv[1]
if func == 'status':
print(status())
elif func == 'start':
print(start())
elif func == 'stop':
print(stop())
elif func == 'restart':
print(restart())
elif func == 'reload':
print(reload())
elif func == 'initd_status':
print(initdStatus())
elif func == 'initd_install':
print(initdInstall())
elif func == 'initd_uninstall':
print(initdUinstall())
elif func == 'run_info':
print(runInfo())
elif func == 'conf':
print(getConf())
elif func == 'run_log':
print(runLog())
elif func == 'config_tpl':
print(configTpl())
elif func == 'read_config_tpl':
print(readConfigTpl())
elif func == 'home_page':
print(homePage())
else:
print('error')
+17
View File
@@ -0,0 +1,17 @@
{
"sort": 7,
"ps": "任务调度管理",
"name": "dztasks",
"title": "dztasks",
"shell": "install.sh",
"versions":["1.1"],
"tip": "soft",
"checks": "server/dztasks",
"path": "server/dztasks",
"display": 1,
"author": "dztasks",
"date": "2024-10-06",
"home": "",
"type": 0,
"pid": "5"
}
@@ -0,0 +1,21 @@
[Unit]
Description=dztasks server
After=network.service
After=syslog.target
[Service]
User=root
Group=root
Type=simple
WorkingDirectory={$SERVER_PATH}/dztasks
ExecStart={$SERVER_PATH}/dztasks/dztasks web
ExecReload=/bin/kill -USR2 $MAINPID
PermissionsStartOnly=true
LimitNOFILE=5000
Restart=on-failure
RestartSec=10
RestartPreventExitStatus=1
PrivateTmp=false
[Install]
WantedBy=multi-user.target
+64
View File
@@ -0,0 +1,64 @@
#!/bin/sh
# chkconfig: 2345 55 25
# description: dztasks Service
### BEGIN INIT INFO
# Provides: dztasks
# Required-Start: $all
# Required-Stop: $all
# Default-Start: 2 3 4 5
# Default-Stop: 0 1 6
# Short-Description: starts dztasks
# Description: starts the MDW-Web
### END INIT INFO
# Simple dztasks init.d script conceived to work on Linux systems
# as it does use of the /proc filesystem.
RED='\033[31m'
GREEN='\033[32m'
YELLOW='\033[33m'
BLUE='\033[34m'
PLAIN='\033[0m'
BOLD='\033[1m'
SUCCESS='[\033[32mOK\033[0m]'
COMPLETE='[\033[32mDONE\033[0m]'
WARN='[\033[33mWARN\033[0m]'
ERROR='[\033[31mERROR\033[0m]'
WORKING='[\033[34m*\033[0m]'
app_start(){
echo "Starting dztasks server..."
cd {$SERVER_PATH}/dztasks
./dztasks web >> {$SERVER_PATH}/dztasks/logs.pl 2>&1 &
}
app_stop(){
echo "dztasks stopp start"
pids=`ps -ef| grep dztasks | grep -v grep | grep -v python | grep -v sh | awk '{print $2}'`
arr=($pids)
for p in ${arr[@]}
do
kill -9 $p > /dev/null 2>&1
done
echo "dztasks stopp end"
}
case "$1" in
start)
app_start
;;
stop)
app_stop
;;
restart|reload)
app_stop
sleep 0.3
app_start
;;
*)
echo "Please use start or stop as first argument"
;;
esac
+85
View File
@@ -0,0 +1,85 @@
#!/bin/bash
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin:/opt/homebrew/bin
export PATH
curPath=`pwd`
rootPath=$(dirname "$curPath")
rootPath=$(dirname "$rootPath")
serverPath=$(dirname "$rootPath")
# cd /Users/midoks/Desktop/mwdev/server/mdserver-web/plugins/dztasks && bash install.sh install 1.0
# cd /wwww/server/mdserver-web/plugins/dztasks && bash install.sh install 1.0
VERSION=$2
sysArch=`arch`
sysName=`uname`
DZ_ARCH_NAME=amd64
if [ "$sysArch" == "arm64" ];then
DZ_ARCH_NAME=arm64
elif [ "$sysArch" == "x86_64" ]; then
DZ_ARCH_NAME=amd64
elif [ "$sysArch" == "aarch64" ]; then
DZ_ARCH_NAME=aarch64
fi
DZ_NAME=linux
if [ "$sysName" == "Darwin" ];then
DZ_NAME=darwin
fi
Install_App()
{
echo '正在安装脚本文件...'
mkdir -p $serverPath/source
mkdir -p $serverPath/source/dztasks
mkdir -p $serverPath/dztasks
FILE_TGZ=dztasks_v${VERSION}_${DZ_NAME}_${DZ_ARCH_NAME}.tar.gz
DZ_DIR=$serverPath/source/dztasks
echo $FILE_TGZ
# https://github.com/midoks/dztasks/releases/download/1.0/dztasks_v1.0_darwin_amd64.tar.gz
if [ ! -f $DZ_DIR/${FILE_TGZ} ];then
wget --no-check-certificate -O $DZ_DIR/${FILE_TGZ} https://github.com/midoks/dztasks/releases/download/${VERSION}/${FILE_TGZ}
fi
cd $DZ_DIR && tar -zxvf ${FILE_TGZ} -C $serverPath/dztasks
echo "${VERSION}" > $serverPath/dztasks/version.pl
cd ${rootPath} && python3 ${rootPath}/plugins/dztasks/index.py start
cd ${rootPath} && python3 ${rootPath}/plugins/dztasks/index.py initd_install
echo '安装dztasks成功!'
}
Uninstall_App()
{
if [ -f /usr/lib/systemd/system/dztasks.service ];then
systemctl stop dztasks
systemctl disable dztasks
rm -rf /usr/lib/systemd/system/dztasks.service
systemctl daemon-reload
fi
if [ -f /lib/systemd/system/dztasks.service ];then
systemctl stop dztasks
systemctl disable dztasks
rm -rf /lib/systemd/system/dztasks.service
systemctl daemon-reload
fi
if [ -f $serverPath/dztasks/initd/dztasks ];then
$serverPath/dztasks/initd/dztasks stop
fi
if [ -d $serverPath/dztasks ];then
rm -rf $serverPath/dztasks
fi
echo "卸载dztasks成功"
}
action=$1
if [ "${1}" == 'install' ];then
Install_App
else
Uninstall_App
fi
+78
View File
@@ -0,0 +1,78 @@
function zdPost(method, version, args,callback){
var loadT = layer.msg('正在获取...', { icon: 16, time: 0, shade: 0.3 });
var req_data = {};
req_data['name'] = 'dztasks';
req_data['func'] = method;
req_data['version'] = version;
if (typeof(args) == 'string'){
req_data['args'] = JSON.stringify(toArrayObject(args));
} else {
req_data['args'] = JSON.stringify(args);
}
$.post('/plugins/run', req_data, function(data) {
layer.close(loadT);
if (!data.status){
//错误展示10S
layer.msg(data.msg,{icon:0,time:2000,shade: [10, '#000']});
return;
}
if(typeof(callback) == 'function'){
callback(data);
}
},'json');
}
function zdPostCallbak(method, version, args,callback){
var loadT = layer.msg('正在获取...', { icon: 16, time: 0, shade: 0.3 });
var req_data = {};
req_data['name'] = 'dztasks';
req_data['func'] = method;
args['version'] = version;
if (typeof(args) == 'string'){
req_data['args'] = JSON.stringify(toArrayObject(args));
} else {
req_data['args'] = JSON.stringify(args);
}
$.post('/plugins/callback', req_data, function(data) {
layer.close(loadT);
if (!data.status){
layer.msg(data.msg,{icon:0,time:2000,shade: [0.3, '#000']});
return;
}
if(typeof(callback) == 'function'){
callback(data);
}
},'json');
}
function commonHomePage(){
zdPost('home_page', '', {}, function(data){
var rdata = $.parseJSON(data.data);
window.open(rdata.data);
});
}
function dzCommonFunc(){
var con = '';
con += '<hr/><p class="conf_p" style="text-align:center;">\
<button class="btn btn-default btn-sm" onclick="commonHomePage()">主页</button>\
</p>';
$(".soft-man-con").html(con);
}
function zdReadme(){
var readme = '<ul class="help-info-text c7">';
readme += '<li>自己修改配置</li>';
readme += '</ul>';
$('.soft-man-con').html(readme);
}
+1 -1
View File
@@ -1,5 +1,5 @@
{
"sort": 7,
"sort": 9,
"ps": "防止恶意IP地址暴力破解服务、站点,禁止导致多个身份验证错误的主机",
"name": "fail2ban",
"title": "fail2ban",
+6 -1
View File
@@ -8,7 +8,6 @@ import re
import json
import io
web_dir = os.getcwd() + "/web"
if os.path.exists(web_dir):
sys.path.append(web_dir)
@@ -16,6 +15,12 @@ if os.path.exists(web_dir):
import core.mw as mw
gd_dir = mw.getServerDir() +'/gdrive/lib'
cmd = 'ls '+gd_dir+' | grep python | cut -d \\ -f 1 | awk \'END {print}\''
info = mw.execShell(cmd)
p = gd_dir +'/'+ info[0].strip() + "/site-packages"
sys.path.append(p)
# -----------------------------
import google.oauth2.credentials
import google_auth_oauthlib.flow
-11
View File
@@ -12,7 +12,6 @@ import json
if sys.platform != "darwin":
os.chdir("/www/server/mdserver-web")
web_dir = os.getcwd() + "/web"
if os.path.exists(web_dir):
sys.path.append(web_dir)
@@ -21,16 +20,6 @@ if os.path.exists(web_dir):
import core.mw as mw
import core.db as db
_ver = sys.version_info
is_py2 = (_ver[0] == 2)
is_py3 = (_ver[0] == 3)
DEBUG = False
if is_py2:
reload(sys)
sys.setdefaultencoding('utf-8')
app_debug = False
if mw.isAppleSystem():
app_debug = True
+1 -1
View File
@@ -1,6 +1,6 @@
{
"hook":["backup"],
"id":998,
"sort":3,
"title":"谷歌云网盘",
"tip":"lib",
"name":"gdrive",
+28 -6
View File
@@ -2,8 +2,15 @@
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin
export PATH
function version_gt() { test "$(echo "$@" | tr " " "\n" | sort -V | head -n 1)" != "$1"; }
function version_le() { test "$(echo "$@" | tr " " "\n" | sort -V | head -n 1)" == "$1"; }
function version_lt() { test "$(echo "$@" | tr " " "\n" | sort -rV | head -n 1)" != "$1"; }
function version_ge() { test "$(echo "$@" | tr " " "\n" | sort -rV | head -n 1)" == "$1"; }
# cd /www/server/mdserver-web/plugins/gdrive && /bin/bash install.sh install 2.0
P_VER=`python3 -V | awk '{print $2}'`
echo "python:$P_VER"
curPath=`pwd`
rootPath=$(dirname "$curPath")
@@ -14,9 +21,9 @@ serverPath=$(dirname "$rootPath")
PATH=$PATH:${rootPath}/bin
export PATH
if [ -f ${rootPath}/bin/activate ];then
source ${rootPath}/bin/activate
fi
# if [ -f ${rootPath}/bin/activate ];then
# source ${rootPath}/bin/activate
# fi
VERSION=$2
@@ -25,9 +32,24 @@ Install_App()
tmp_ping=`ping -c 1 google.com 2>&1`
echo $tmp_ping
if [ $? -eq 0 ];then
tmp=`python -V 2>&1|awk '{print $2}'`
pVersion=${tmp:0:3}
GDDIR=$serverPath/gdrive
mkdir -p $GDDIR
if [ ! -f ${GDDIR}/bin/activate ];then
if version_ge "$P_VER" "3.11.0" ;then
echo "python3 > 3.11"
cd ${GDDIR} && python3 -m venv ${GDDIR}
else
echo "python3 < 3.10"
cd ${GDDIR} && python3 -m venv .
fi
cd ${GDDIR} && source ${GDDIR}/bin/activate
else
cd ${GDDIR} && source ${GDDIR}/bin/activate
fi
tmp=`python3 -V 2>&1|awk '{print $2}'`
pVersion=${tmp:0:3}
which pip
if [ "$?" -eq "0" ];then
@@ -59,7 +81,7 @@ Install_App()
fi
echo '正在安装脚本文件...'
mkdir -p $serverPath/gdrive
echo "${VERSION}" > $serverPath/gdrive/version.pl
echo '安装完成'
else
+1 -1
View File
@@ -189,7 +189,7 @@ function gdList(file_id){
if(rdata.status === false){
showMsg(rdata.msg,function(){
authApi();
},{icon:2},2000);
},{icon:2});
return;
}
+2 -1
View File
@@ -30,7 +30,8 @@ unset GIT_DIR
cd $GIT_PROJECT_DIR && git pull
# cd $GIT_PROJECT_DIR && git pull
cd $GIT_PROJECT_DIR && sudo git pull
# func 2
# cd $GIT_PROJECT_DIR && env -i git pull origin master
+1
View File
@@ -14,6 +14,7 @@
<p class="bgw" onclick="pluginService('gorse');">服务</p>
<p onclick="pluginInitD('gorse');">自启动</p>
<p onclick="pluginConfigTpl('gorse',$('.plugin_version').attr('version'));">配置修改</p>
<p onclick="gorseCommonFunc();">常用功能</p>
<p onclick="pluginLogs('gorse','','run_log');">运行日志</p>
<p onclick="gorseReadme();">相关说明</p>
+36 -1
View File
@@ -125,7 +125,7 @@ def initRedisConf():
requirepass = ""
conf = mw.getServerDir() + '/redis/redis.conf'
content = mw.readFile(conf)
rep = r"^(requirepass" + r"\)\s*([.0-9A-Za-z_& ~]+)"
rep = r"^(requirepass)\s*([.0-9A-Za-z_& ~]+)"
tmp = re.search(rep, content, re.M)
if tmp:
requirepass = tmp.groups()[1]
@@ -304,6 +304,34 @@ def initdUinstall():
def runLog():
return getServerDir() + '/logs.pl'
def getGorseInfo():
conf_file = getConf()
content = mw.readFile(conf_file)
rdata = {}
rep = r'dashboard_user_name\s*=\s*"(.*)"'
tmp = re.search(rep, content)
tmp = re.search(rep, content, re.M)
if tmp:
rdata['dashboard_user_name'] = tmp.groups()[0]
rep = r'dashboard_password\s*=\s*"(.*)"'
tmp = re.search(rep, content)
tmp = re.search(rep, content, re.M)
if tmp:
rdata['dashboard_password'] = tmp.groups()[0]
rep = r'http_port\s*=\s*(.*)'
tmp = re.search(rep, content)
tmp = re.search(rep, content, re.M)
if tmp:
rdata['http_port'] = tmp.groups()[0]
rdata['ip'] = mw.getHostAddr()
return mw.returnJson(True,'ok', rdata)
def installPreInspection():
redis_path = mw.getServerDir() + "/redis"
if not os.path.exists(redis_path):
@@ -312,6 +340,11 @@ def installPreInspection():
mongodb_path = mw.getServerDir() + "/mongodb"
if not os.path.exists(mongodb_path):
return "默认需要安装MongoDB"
if not mw.isAppleSystem():
glibc_ver = mw.getGlibcVersion()
if float(glibc_ver) < 2.32:
return '当前libc{}过低,需要大于2.31'.format(glibc_ver)
return 'ok'
if __name__ == "__main__":
@@ -342,5 +375,7 @@ if __name__ == "__main__":
print(configTpl())
elif func == 'read_config_tpl':
print(readConfigTpl())
elif func == 'info':
print(getGorseInfo())
else:
print('error')
+31 -1
View File
@@ -54,8 +54,38 @@ function gorsePostCallbak(method, version, args,callback){
}
function gorseReadme(){
function gorseCommonFunc(){
gorsePost('info', '', {}, function(rdata){
var rdata = $.parseJSON(rdata.data);
var info = rdata['data'];
var con = '<p class="conf_p">\
<span>用户名</span>\
<input class="bt-input-text mr5" type="text" value="' + info.dashboard_user_name + '">\
</p>';
con += '<p class="conf_p">\
<span>密码</span>\
<input class="bt-input-text mr5" type="text" value="' + info.dashboard_password +'">\
</p>';
con += '<p class="conf_p">\
<span>端口</span>\
<input class="bt-input-text mr5" type="text" value="' + info.http_port +'">\
</p>';
con += '<hr/><p class="conf_p" style="text-align:center;">\
<button id="open_url" class="btn btn-default btn-sm">打开Gorse</button>\
</p>';
$(".soft-man-con").html(con);
$('#open_url').click(function(){
var url = 'http://' + info.ip + ':' + info.http_port;
window.open(url);
copyText(url);
});
});
}
function gorseReadme(){
var readme = '<ul class="help-info-text c7">';
readme += '<li>参考官方</li>';
+39
View File
@@ -0,0 +1,39 @@
{
"password": "{CRYPT-SHA512}$6$WheNHdlVwDoL4s.x$DrZ10TpIGQa5wd0jbvtm8eaTleJCf1nec3ihOaNwMdPUKVFCphXwtnTSmFFXjhGa45RlrSEWhDVyjLCMiV\/.c. V2hlTkhkbFZ3RG9MNHMueA==",
"default": "lam",
"sessionTimeout": "30",
"hideLoginErrorDetails": "false",
"logLevel": "4",
"logDestination": "SYSLOG",
"allowedHosts": "",
"passwordMinLength": "10",
"passwordMinUpper": "0",
"passwordMinLower": "0",
"passwordMinNumeric": "0",
"passwordMinClasses": "0",
"passwordMinSymbol": "0",
"checkedRulesCount": "-1",
"passwordMustNotContainUser": "false",
"passwordMustNotContain3Chars": "false",
"externalPwdCheckUrl": "",
"errorReporting": "default",
"allowedHostsSelfService": "",
"license": "",
"licenseEmailFrom": "",
"licenseEmailTo": "",
"licenseWarningType": "all",
"licenseEmailDateSent": "",
"mailServer": "",
"mailUser": "",
"mailPassword": "",
"mailEncryption": "TLS",
"mailAttribute": "mail",
"mailBackupAttribute": "passwordselfresetbackupmail",
"configDatabaseType": "files",
"configDatabaseServer": "",
"configDatabasePort": "",
"configDatabaseName": "",
"configDatabaseUser": "",
"configDatabasePassword": "",
"moduleSettings": "eyJyZXF1ZXN0QWNjZXNzIjp7Imhpc3RvcnlSZXRlbnRpb25QZXJpb2QiOiIzNjUwIiwiZXhwaXJhdGlvblBlcmlvZCI6IjMwIn19"
}
+38
View File
@@ -0,0 +1,38 @@
server
{
listen 888;
server_name 127.0.0.1;
index index.html index.htm index.php;
root {$SERVER_PATH}/lam;
#error_page 404 /404.html;
include {$PHP_CONF_PATH}/enable-php-{$PHP_VER}.conf;
#AUTH_START
auth_basic "Authorization";
auth_basic_user_file {$SERVER_PATH}/lam/pma.pass;
#AUTH_END
location ~ .*\.(gif|jpg|jpeg|png|bmp|swf)$
{
expires 30d;
}
location ~ .*\.(js|css)?$
{
expires 12h;
}
location ~ /.*\.(log|pass|json|pl)$ {
deny all;
}
location ~ /\.
{
deny all;
}
access_log {$SERVER_PATH}/lam/access.log;
error_log {$SERVER_PATH}/lam/error.log;
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 3.9 KiB

+24
View File
@@ -0,0 +1,24 @@
<div class="bt-form">
<div class="bt-w-main">
<div class="bt-w-menu">
<p class="bgw" onclick="pluginService('lam');">服务</p>
<p onclick="pluginConfig('lam');">重写模版</p>
<p onclick="homePage()">主页</p>
<p onclick="phpVer(56)">PHP版本</p>
<p onclick="safeConf();">安全设置</p>
<p onclick="pluginLogs('lam','','access_log');">访问日志</p>
<p onclick="pluginLogs('lam','','error_log');">错误日志</p>
<p onclick="pluginConfig('lam','','config_inc');" title="config.inc.php">配置</p>
</div>
<div class="bt-w-con pd15">
<div class="soft-man-con"></div>
</div>
</div>
</div>
<script type="text/javascript">
resetPluginWinHeight(500);
$.getScript( "/plugins/file?name=lam&f=js/lam.js", function(){
pluginService('lam');
});
</script>
+476
View File
@@ -0,0 +1,476 @@
# coding:utf-8
import sys
import io
import os
import time
import re
import json
web_dir = os.getcwd() + "/web"
if os.path.exists(web_dir):
sys.path.append(web_dir)
os.chdir(web_dir)
import core.mw as mw
import thisdb
from utils.site import sites as MwSites
app_debug = False
if mw.isAppleSystem():
app_debug = True
def getPluginName():
return 'lam'
def getPluginDir():
return mw.getPluginDir() + '/' + getPluginName()
def getServerDir():
return mw.getServerDir() + '/' + getPluginName()
def getArgs():
args = sys.argv[2:]
tmp = {}
args_len = len(args)
if args_len == 1:
t = args[0].strip('{').strip('}')
t = t.split(':')
tmp[t[0]] = t[1]
elif args_len > 1:
for i in range(len(args)):
t = args[i].split(':')
tmp[t[0]] = t[1]
return tmp
def checkArgs(data, ck=[]):
for i in range(len(ck)):
if not ck[i] in data:
return (False, mw.returnJson(False, '参数:(' + ck[i] + ')没有!'))
return (True, mw.returnJson(True, 'ok'))
def getConf():
return mw.getServerDir() + '/web_conf/nginx/vhost/lam.conf'
def getConfInc():
return getServerDir() + "/" + getCfg()['path'] + '/config/config.cfg'
def getPort():
file = getConf()
content = mw.readFile(file)
rep = r'listen\s*(.*);'
tmp = re.search(rep, content)
return tmp.groups()[0].strip()
def getHomePage():
try:
port = getPort()
ip = '127.0.0.1'
if not mw.isAppleSystem():
ip = mw.getLocalIp()
cfg = getCfg()
auth = cfg['username']+':'+cfg['password']
rand_path = cfg['path']
url = 'http://' + auth + '@' + ip + ':' + port + '/' + rand_path + '/templates/login.php'
return mw.returnJson(True, 'OK', url)
except Exception as e:
return mw.returnJson(False, '插件未启动!')
def getPhpVer(expect=83):
php_vers = MwSites.instance().getPhpVersion()
v = php_vers['data']
is_find = False
for i in range(len(v)):
t = str(v[i]['version'])
if (t == expect):
is_find = True
return str(t)
expect_str = str(expect)
new_ex = expect_str[0:1]+"."+expect_str[1:2]
if t.find(new_ex) > -1:
is_find = True
return str(t)
if not is_find:
if len(v) > 1:
return v[1]['version']
return v[0]['version']
return str(expect)
def getCachePhpVer():
cacheFile = getServerDir() + '/php.pl'
v = ''
if os.path.exists(cacheFile):
v = mw.readFile(cacheFile)
else:
v = getPhpVer()
mw.writeFile(cacheFile, v)
return v
def contentReplace(content):
service_path = mw.getServerDir()
php_ver = getCachePhpVer()
tmp = mw.execShell('cat /dev/urandom | head -n 32 | md5sum | head -c 16')
blowfish_secret = tmp[0].strip()
# print php_ver
php_conf_dir = mw.getServerDir() + '/web_conf/php/conf'
content = content.replace('{$ROOT_PATH}', mw.getFatherDir())
content = content.replace('{$SERVER_PATH}', service_path)
content = content.replace('{$PHP_CONF_PATH}', php_conf_dir)
content = content.replace('{$PHP_VER}', php_ver)
content = content.replace('{$BLOWFISH_SECRET}', blowfish_secret)
cfg = getCfg()
content = content.replace('{$PMA_PATH}', cfg['path'])
port = cfg["port"]
rep = r'listen\s*(.*);'
content = re.sub(rep, "listen " + port + ';', content)
return content
def initCfg():
cfg = getServerDir() + "/cfg.json"
if not os.path.exists(cfg):
data = {}
data['port'] = '987'
data['path'] = ''
data['username'] = 'admin'
data['password'] = 'admin'
mw.writeFile(cfg, json.dumps(data))
def setCfg(key, val):
cfg = getServerDir() + "/cfg.json"
data = mw.readFile(cfg)
data = json.loads(data)
data[key] = val
mw.writeFile(cfg, json.dumps(data))
def getCfg():
cfg = getServerDir() + "/cfg.json"
data = mw.readFile(cfg)
data = json.loads(data)
return data
def returnCfg():
cfg = getServerDir() + "/cfg.json"
data = mw.readFile(cfg)
return data
def status():
conf = getConf()
conf_inc = getServerDir() + "/" + getCfg()["path"] + '/config/config.cfg'
# 两个文件都在,才算启动成功
if os.path.exists(conf) and os.path.exists(conf_inc):
return 'start'
return 'stop'
def __release_port(port):
from collections import namedtuple
try:
from utils.firewall import Firewall as MwFirewall
MwFirewall.instance().addAcceptPort(port, 'LAM默认端口', 'port')
return port
except Exception as e:
return "Release failed {}".format(e)
def __delete_port(port):
from collections import namedtuple
try:
from utils.firewall import Firewall as MwFirewall
MwFirewall.instance().delAcceptPortCmd(port, 'tcp')
return port
except Exception as e:
return "Release failed {}".format(e)
def openPort():
conf = getCfg()
port = conf['port']
for i in [port]:
__release_port(i)
return True
def delPort():
conf = getCfg()
port = conf['port']
for i in [port]:
__delete_port(i)
return True
def start():
initCfg()
openPort()
pma_dir = getServerDir() + "/lam"
if os.path.exists(pma_dir):
rand_str = mw.getRandomString(6)
rand_str = rand_str.lower()
pma_dir_dst = pma_dir + "_" + rand_str
mw.execShell("mv " + pma_dir + " " + pma_dir_dst)
mw.execShell("chown -R www:www " + pma_dir_dst)
mw.execShell("chmod -R 777 " + pma_dir_dst+'/sess')
mw.execShell("chmod -R 777 " + pma_dir_dst+'/tmp')
setCfg('path', 'lam_' + rand_str)
file_tpl = getPluginDir() + '/conf/lam.conf'
file_run = getConf()
if not os.path.exists(file_run):
centent = mw.readFile(file_tpl)
centent = contentReplace(centent)
mw.writeFile(file_run, centent)
pma_path = getServerDir() + '/pma.pass'
if not os.path.exists(pma_path):
username = mw.getRandomString(8)
password = mw.getRandomString(10)
pass_cmd = username + ':' + mw.hasPwd(password)
setCfg('username', username)
setCfg('password', password)
mw.writeFile(pma_path, pass_cmd)
tmp = getServerDir() + "/" + getCfg()["path"] + '/tmp'
if not os.path.exists(tmp):
os.mkdir(tmp)
mw.execShell("chown -R www:www " + tmp)
conf_run = getServerDir() + "/" + getCfg()["path"] + '/config/config.cfg'
if not os.path.exists(conf_run):
conf_tpl = getPluginDir() + '/conf/config.cfg'
centent = mw.readFile(conf_tpl)
centent = contentReplace(centent)
mw.writeFile(conf_run, centent)
log_a = accessLog()
log_e = errorLog()
for i in [log_a, log_e]:
if os.path.exists(i):
cmd = "echo '' > " + i
mw.execShell(cmd)
mw.restartWeb()
return 'ok'
def stop():
conf = getConf()
if os.path.exists(conf):
os.remove(conf)
delPort()
mw.restartWeb()
return 'ok'
def restart():
return start()
def reload():
file_tpl = getPluginDir() + '/conf/lam.conf'
file_run = getConf()
if os.path.exists(file_run):
centent = mw.readFile(file_tpl)
centent = contentReplace(centent)
mw.writeFile(file_run, centent)
return start()
def setPhpVer():
args = getArgs()
if not 'phpver' in args:
return 'phpver missing'
cacheFile = getServerDir() + '/php.pl'
mw.writeFile(cacheFile, args['phpver'])
file_tpl = getPluginDir() + '/conf/lam.conf'
file_run = getConf()
content = mw.readFile(file_tpl)
content = contentReplace(content)
mw.writeFile(file_run, content)
mw.restartWeb()
return 'ok'
def getSetPhpVer():
cacheFile = getServerDir() + '/php.pl'
if os.path.exists(cacheFile):
return mw.readFile(cacheFile).strip()
return ''
def getPmaOption():
data = getCfg()
return mw.returnJson(True, 'ok', data)
def getPmaPort():
try:
port = getPort()
return mw.returnJson(True, 'OK', port)
except Exception as e:
# print(e)
return mw.returnJson(False, '插件未启动!')
def setPmaPort():
args = getArgs()
data = checkArgs(args, ['port'])
if not data[0]:
return data[1]
port = args['port']
if port == '80':
return mw.returnJson(False, '80端不能使用!')
file = getConf()
if not os.path.exists(file):
return mw.returnJson(False, '插件未启动!')
content = mw.readFile(file)
rep = r'listen\s*(.*);'
content = re.sub(rep, "listen " + port + ';', content)
mw.writeFile(file, content)
setCfg("port", port)
mw.restartWeb()
return mw.returnJson(True, '修改成功!')
def setPmaUsername():
args = getArgs()
data = checkArgs(args, ['username'])
if not data[0]:
return data[1]
username = args['username']
setCfg('username', username)
cfg = getCfg()
pma_path = getServerDir() + '/pma.pass'
username = mw.getRandomString(10)
pass_cmd = cfg['username'] + ':' + mw.hasPwd(cfg['password'])
mw.writeFile(pma_path, pass_cmd)
mw.restartWeb()
return mw.returnJson(True, '修改成功!')
def setPmaPassword():
args = getArgs()
data = checkArgs(args, ['password'])
if not data[0]:
return data[1]
password = args['password']
setCfg('password', password)
cfg = getCfg()
pma_path = getServerDir() + '/pma.pass'
username = mw.getRandomString(10)
pass_cmd = cfg['username'] + ':' + mw.hasPwd(cfg['password'])
mw.writeFile(pma_path, pass_cmd)
mw.restartWeb()
return mw.returnJson(True, '修改成功!')
def setPmaPath():
args = getArgs()
data = checkArgs(args, ['path'])
if not data[0]:
return data[1]
path = args['path']
if len(path) < 5:
return mw.returnJson(False, '不能小于5位!')
old_path = getServerDir() + "/" + getCfg()['path']
new_path = getServerDir() + "/" + path
mw.execShell("mv " + old_path + " " + new_path)
setCfg('path', path)
return mw.returnJson(True, '修改成功!')
def accessLog():
return getServerDir() + '/access.log'
def errorLog():
return getServerDir() + '/error.log'
def installVersion():
return mw.readFile(getServerDir() + '/version.pl')
if __name__ == "__main__":
func = sys.argv[1]
if func == 'status':
print(status())
elif func == 'start':
print(start())
elif func == 'stop':
print(stop())
elif func == 'restart':
print(restart())
elif func == 'reload':
print(reload())
elif func == 'conf':
print(getConf())
elif func == 'version':
print(installVersion())
elif func == 'get_cfg':
print(returnCfg())
elif func == 'config_inc':
print(getConfInc())
elif func == 'get_home_page':
print(getHomePage())
elif func == 'set_php_ver':
print(setPhpVer())
elif func == 'get_set_php_ver':
print(getSetPhpVer())
elif func == 'get_pma_port':
print(getPmaPort())
elif func == 'set_pma_port':
print(setPmaPort())
elif func == 'get_pma_option':
print(getPmaOption())
elif func == 'set_pma_username':
print(setPmaUsername())
elif func == 'set_pma_password':
print(setPmaPassword())
elif func == 'set_pma_path':
print(setPmaPath())
elif func == 'access_log':
print(accessLog())
elif func == 'error_log':
print(errorLog())
else:
print('error')
+15
View File
@@ -0,0 +1,15 @@
{
"title":"LAM",
"tip":"soft",
"name":"lam",
"type":"运行环境",
"ps":"LDAP管理工具(LAM)",
"versions":["9.0"],
"shell":"install.sh",
"checks":"server/lam",
"path": "server/lam",
"author":"gruberroland",
"home":"https://github.com/LDAPAccountManager",
"date":"2025-1-28",
"pid": "2"
}
+90
View File
@@ -0,0 +1,90 @@
#!/bin/bash
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin:/opt/homebrew/bin
export PATH
curPath=`pwd`
rootPath=$(dirname "$curPath")
rootPath=$(dirname "$rootPath")
serverPath=$(dirname "$rootPath")
# cd /www/server/mdserver-web/plugins/lam && bash install.sh install 9.0
# cd /www/server/mdserver-web && python3 plugins/lam/index.py start
if [ -f ${rootPath}/bin/activate ];then
source ${rootPath}/bin/activate
fi
if [ "$sys_os" == "Darwin" ];then
BAK='_bak'
else
BAK=''
fi
sysName=`uname`
echo "use system: ${sysName}"
if [ "${sysName}" == "Darwin" ]; then
OSNAME='macos'
elif grep -Eqi "CentOS" /etc/issue || grep -Eq "CentOS" /etc/*-release; then
OSNAME='centos'
elif grep -Eqi "Fedora" /etc/issue || grep -Eq "Fedora" /etc/*-release; then
OSNAME='fedora'
elif grep -Eqi "Debian" /etc/issue || grep -Eq "Debian" /etc/*-release; then
OSNAME='debian'
elif grep -Eqi "Ubuntu" /etc/issue || grep -Eq "Ubuntu" /etc/*-release; then
OSNAME='ubuntu'
elif grep -Eqi "Raspbian" /etc/issue || grep -Eq "Raspbian" /etc/*-release; then
OSNAME='raspbian'
else
OSNAME='unknow'
fi
Install_App()
{
if [ -d $serverPath/lam ];then
exit 0
fi
mkdir -p ${serverPath}/lam
mkdir -p ${serverPath}/source/lam
echo "${1}" > ${serverPath}/lam/version.pl
VER=$1
# https://github.com/LDAPAccountManager/lam/releases/download/9.0/ldap-account-manager-9.0.tar.bz2
FDIR=ldap-account-manager-${VER}
FILE=ldap-account-manager-${VER}.tar.bz2
DOWNLOAD=https://github.com/LDAPAccountManager/lam/releases/download/9.0/${FILE}
if [ ! -f $serverPath/source/phpmyadmin/$FILE ];then
wget --no-check-certificate -O $serverPath/source/lam/$FILE $DOWNLOAD
fi
if [ ! -d $serverPath/source/lam/$FDIR ];then
cd $serverPath/source/lam && tar jxvf $FILE
fi
cp -r $serverPath/source/lam/$FDIR $serverPath/lam/
cd $serverPath/lam/ && mv $FDIR lam
# rm -rf $serverPath/source/lam/$FDIR
cd ${rootPath} && python3 ${rootPath}/plugins/lam/index.py start
echo '安装完成'
}
Uninstall_App()
{
cd ${rootPath} && python3 ${rootPath}/plugins/lam/index.py stop
rm -rf ${serverPath}/lam
echo '卸载完成'
}
action=$1
if [ "${1}" == 'install' ];then
Install_App $2
else
Uninstall_App $2
fi
+164
View File
@@ -0,0 +1,164 @@
function str2Obj(str){
var data = {};
kv = str.split('&');
for(i in kv){
v = kv[i].split('=');
data[v[0]] = v[1];
}
return data;
}
function pmaPost(method,args,callback){
var _args = null;
if (typeof(args) == 'string'){
_args = JSON.stringify(str2Obj(args));
} else {
_args = JSON.stringify(args);
}
var loadT = layer.msg('正在获取...', { icon: 16, time: 0, shade: 0.3 });
$.post('/plugins/run', {name:'lam', func:method, args:_args}, function(data) {
layer.close(loadT);
if (!data.status){
layer.msg(data.msg,{icon:0,time:2000,shade: [0.3, '#000']});
return;
}
if(typeof(callback) == 'function'){
callback(data);
}
},'json');
}
function pmaAsyncPost(method,args){
var _args = null;
if (typeof(args) == 'string'){
_args = JSON.stringify(str2Obj(args));
} else {
_args = JSON.stringify(args);
}
return syncPost('/plugins/run', {name:'lam', func:method, args:_args});
}
function homePage(){
pmaPost('get_home_page', '', function(data){
var rdata = $.parseJSON(data.data);
if (!rdata.status){
layer.msg(rdata.msg,{icon:0,time:2000,shade: [0.3, '#000']});
return;
}
var con = '<button class="btn btn-default btn-sm" onclick="window.open(\'' + rdata.data + '\')">主页</button>';
$(".soft-man-con").html(con);
});
}
//phpmyadmin切换php版本
function phpVer(version) {
var _version = pmaAsyncPost('get_set_php_ver','')
if (_version['data'] != ''){
version = _version['data'];
}
$.post('/site/get_php_version', function(data) {
var rdata = data['data'];
// console.log(rdata);
var body = "<div class='ver line'><span class='tname'>PHP版本</span><select id='phpver' class='bt-input-text mr20' name='phpVersion' style='width:110px'>";
var optionSelect = '';
for (var i = 0; i < rdata.length; i++) {
optionSelect = rdata[i].version == version ? 'selected' : '';
body += "<option value='" + rdata[i].version + "' " + optionSelect + ">" + rdata[i].name + "</option>"
}
body += '</select><button class="btn btn-success btn-sm" onclick="phpVerChange(\'phpversion\',\'get\')">保存</button></div>';
$(".soft-man-con").html(body);
},'json');
}
function phpVerChange(type, msg) {
var phpver = $("#phpver").val();
pmaPost('set_php_ver', 'phpver='+phpver, function(data){
if ( data.data == 'ok' ){
layer.msg('设置成功!',{icon:1,time:2000,shade: [0.3, '#000']});
} else {
layer.msg('设置失败!',{icon:2,time:2000,shade: [0.3, '#000']});
}
});
}
//phpmyadmin安全设置
function safeConf() {
pmaPost('get_pma_option', {}, function(rdata){
var rdata = $.parseJSON(rdata.data);
if (!rdata.status){
layer.msg(rdata.msg,{icon:2,time:2000,shade: [0.3, '#000']});
return;
}
var cfg = rdata.data;
var con = '<div class="ver line">\
<span class="tname">访问端口</span>\
<input style="width:110px" class="bt-input-text phpmyadmindk mr20" name="Name" id="pmport" value="' + cfg['port'] + '" placeholder="phpmyadmin访问端口" maxlength="5" type="number">\
<button class="btn btn-success btn-sm" onclick="setPamPort()">保存</button>\
</div>\
<div class="ver line">\
<span class="tname">用户名</span>\
<input style="width:110px" class="bt-input-text mr20" name="username" id="pmport" value="' + cfg['username'] + '" placeholder="认证用户名" type="text">\
<button class="btn btn-success btn-sm" onclick="setPmaUsername()">保存</button>\
</div>\
<div class="ver line">\
<span class="tname">密码</span>\
<input style="width:110px" class="bt-input-text mr20" name="password" id="pmport" value="' + cfg['password'] + '" placeholder="密码" type="text">\
<button class="btn btn-success btn-sm" onclick="setPmaPassword()">保存</button>\
</div>\
<hr/>\
<div class="ver line">\
<span class="tname">路径名</span>\
<input style="width:180px" class="bt-input-text mr20" name="path" id="pmport" value="' + cfg['path'] + '" placeholder="" type="text">\
<button class="btn btn-success btn-sm" onclick="setPmaPath()">保存</button>\
</div>';
$(".soft-man-con").html(con);
});
}
function setPmaUsername(){
var username = $("input[name=username]").val();
pmaPost('set_pma_username',{'username':username}, function(data){
var rdata = $.parseJSON(data.data);
layer.msg(rdata.msg, { icon: rdata.status ? 1 : 2 });
});
}
function setPmaPassword(){
var password = $("input[name=password]").val();
pmaPost('set_pma_password',{'password':password}, function(data){
var rdata = $.parseJSON(data.data);
layer.msg(rdata.msg, { icon: rdata.status ? 1 : 2 });
});
}
function setPmaPath(){
var path = $("input[name=path]").val();
pmaPost('set_pma_path',{'path':path}, function(data){
var rdata = $.parseJSON(data.data);
layer.msg(rdata.msg, { icon: rdata.status ? 1 : 2 });
});
}
//修改phpmyadmin端口
function setPamPort() {
var pmport = $("#pmport").val();
if (pmport < 80 || pmport > 65535) {
layer.msg('端口范围不合法!', { icon: 2 });
return;
}
var data = 'port=' + pmport;
pmaPost('set_pma_port',data, function(data){
var rdata = $.parseJSON(data.data);
layer.msg(rdata.msg, { icon: rdata.status ? 1 : 2 });
});
}
+17
View File
@@ -0,0 +1,17 @@
#
# LDAP Defaults
#
# See ldap.conf(5) for details
# This file should be world readable but not world writable.
BASE dc=mw,dc=com
URI ldap://{$IP} ldap://{$IP}:666
#SIZELIMIT 12
#TIMELIMIT 15
#DEREF never
# TLS certificates (needed for GnuTLS)
TLS_CACERT /etc/ssl/certs/ca-certificates.crt
Binary file not shown.

After

Width:  |  Height:  |  Size: 3.9 KiB

+30
View File
@@ -0,0 +1,30 @@
<style>
.overflow_hide {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
vertical-align: middle;
}
</style>
<div class="bt-form">
<div class='plugin_version'></div>
<div class="bt-w-main">
<div class="bt-w-menu">
<p class="bgw" onclick="pluginService('ldap');">服务</p>
<p onclick="pluginInitD('ldap');">自启动</p>
<p onclick="pluginConfigTpl('ldap',$('.plugin_version').attr('version'));">配置修改</p>
<p onclick="pluginLogs('ldap','','run_log');">运行日志</p>
<p onclick="ladpReadme();">相关说明</p>
</div>
<div class="bt-w-con pd15">
<div class="soft-man-con" style="height: 520px; overflow: auto;"></div>
</div>
</div>
</div>
<script type="text/javascript">
$.getScript( "/plugins/file?name=ldap&f=js/ldap.js", function(){
pluginService('ldap', $('.plugin_version').attr('version'));
});
</script>
+354
View File
@@ -0,0 +1,354 @@
# coding:utf-8
import sys
import io
import os
import time
import re
web_dir = os.getcwd() + "/web"
if os.path.exists(web_dir):
sys.path.append(web_dir)
os.chdir(web_dir)
import core.mw as mw
app_debug = False
if mw.isAppleSystem():
app_debug = True
def getPluginName():
return 'ldap'
def getPluginDir():
return mw.getPluginDir() + '/' + getPluginName()
def getServerDir():
return mw.getServerDir() + '/' + getPluginName()
def getInitDFile():
current_os = mw.getOs()
if current_os == 'darwin':
return '/tmp/' + getPluginName()
if current_os.startswith('freebsd'):
return '/etc/rc.d/' + getPluginName()
return '/etc/init.d/' + getPluginName()
def getConf():
# path = getServerDir() + "/redis.conf"
path = "/etc/ldap/ldap.conf"
return path
def getConfTpl():
path = getPluginDir() + "/config/ldap.conf"
return path
def getInitDTpl():
path = getPluginDir() + "/init.d/" + getPluginName() + ".tpl"
return path
def getArgs():
args = sys.argv[3:]
tmp = {}
args_len = len(args)
if args_len == 1:
t = args[0].strip('{').strip('}')
if t.strip() == '':
tmp = []
else:
t = t.split(':')
tmp[t[0]] = t[1]
tmp[t[0]] = t[1]
elif args_len > 1:
for i in range(len(args)):
t = args[i].split(':')
tmp[t[0]] = t[1]
return tmp
def checkArgs(data, ck=[]):
for i in range(len(ck)):
if not ck[i] in data:
return (False, mw.returnJson(False, '参数:(' + ck[i] + ')没有!'))
return (True, mw.returnJson(True, 'ok'))
def configTpl():
path = "/etc/ldap/schema"
pathFile = os.listdir(path)
tmp = []
for one in pathFile:
file = path + '/' + one
tmp.append(file)
return mw.getJson(tmp)
def readConfigTpl():
args = getArgs()
data = checkArgs(args, ['file'])
if not data[0]:
return data[1]
content = mw.readFile(args['file'])
content = contentReplace(content)
return mw.returnJson(True, 'ok', content)
def getPidFile():
file = getConf()
content = mw.readFile(file)
rep = r'pidfile\s*(.*)'
tmp = re.search(rep, content)
return tmp.groups()[0].strip()
def status():
pid_file = "/var/run/slapd/slapd.pid"
if not os.path.exists(pid_file):
return 'stop'
# data = mw.execShell(
# "ps aux|grep redis |grep -v grep | grep -v python | grep -v mdserver-web | awk '{print $2}'")
# if data[0] == '':
# return 'stop'
return 'start'
def contentReplace(content):
service_path = mw.getServerDir()
content = content.replace('{$ROOT_PATH}', mw.getFatherDir())
return content
def initDreplace():
service_path = mw.getServerDir()
conf = getConf()
conf_tpl = getConfTpl()
if not os.path.exists(conf):
content = mw.readFile(conf_tpl)
content = contentReplace(content)
mw.writeFile(conf, content)
return True
def ladpOp(method):
initDreplace()
current_os = mw.getOs()
if current_os == "darwin":
return 'ok'
if current_os.startswith("freebsd"):
data = mw.execShell('service slapd ' + method)
if data[1] == '':
return 'ok'
return data[1]
data = mw.execShell('systemctl ' + method + ' slapd')
if data[1] == '':
return 'ok'
return data[1]
def start():
return ladpOp('start')
def stop():
return ladpOp('stop')
def restart():
status = ladpOp('restart')
log_file = runLog()
mw.execShell("echo '' > " + log_file)
return status
def reload():
return ladpOp('reload')
def getPort():
conf = getConf()
content = mw.readFile(conf)
rep = r"^(port)\s*([.0-9A-Za-z_& ~]+)"
tmp = re.search(rep, content, re.M)
if tmp:
return tmp.groups()[1]
return '6379'
def initdStatus():
current_os = mw.getOs()
if current_os == 'darwin':
return "Apple Computer does not support"
if current_os.startswith('freebsd'):
initd_bin = getInitDFile()
if os.path.exists(initd_bin):
return 'ok'
shell_cmd = 'systemctl status slapd | grep loaded | grep "enabled;"'
data = mw.execShell(shell_cmd)
if data[0] == '':
return 'fail'
return 'ok'
def initdInstall():
current_os = mw.getOs()
if current_os == 'darwin':
return "Apple Computer does not support"
# freebsd initd install
if current_os.startswith('freebsd'):
import shutil
source_bin = initDreplace()
initd_bin = getInitDFile()
shutil.copyfile(source_bin, initd_bin)
mw.execShell('chmod +x ' + initd_bin)
mw.execShell('sysrc slapd_enable="YES"')
return 'ok'
mw.execShell('systemctl enable slapd')
return 'ok'
def initdUinstall():
current_os = mw.getOs()
if current_os == 'darwin':
return "Apple Computer does not support"
if current_os.startswith('freebsd'):
initd_bin = getInitDFile()
os.remove(initd_bin)
mw.execShell('sysrc slapd_enable="NO"')
return 'ok'
mw.execShell('systemctl disable slapd')
return 'ok'
def runLog():
return getServerDir() + '/data/redis.log'
def getRedisConfInfo():
conf = getConf()
gets = [
{'name': 'bind', 'type': 2, 'ps': '绑定IP(修改绑定IP可能会存在安全隐患)','must_show':1},
{'name': 'port', 'type': 2, 'ps': '绑定端口','must_show':1},
{'name': 'timeout', 'type': 2, 'ps': '空闲链接超时时间,0表示不断开','must_show':1},
{'name': 'maxclients', 'type': 2, 'ps': '最大连接数','must_show':1},
{'name': 'databases', 'type': 2, 'ps': '数据库数量','must_show':1},
{'name': 'requirepass', 'type': 2, 'ps': 'redis密码,留空代表没有设置密码','must_show':1},
{'name': 'maxmemory', 'type': 2, 'ps': 'MB,最大使用内存,0表示不限制','must_show':1},
{'name': 'slaveof', 'type': 2, 'ps': '同步主库地址','must_show':0},
{'name': 'masterauth', 'type': 2, 'ps': '同步主库密码', 'must_show':0}
]
content = mw.readFile(conf)
result = []
for g in gets:
rep = r"^(" + g['name'] + r'\)\s*([.0-9A-Za-z_& ~]+)'
tmp = re.search(rep, content, re.M)
if not tmp:
if g['must_show'] == 0:
continue
g['value'] = ''
result.append(g)
continue
g['value'] = tmp.groups()[1]
if g['name'] == 'maxmemory':
g['value'] = g['value'].strip("mb")
result.append(g)
return result
def getRedisConf():
data = getRedisConfInfo()
return mw.getJson(data)
def submitRedisConf():
gets = ['bind', 'port', 'timeout', 'maxclients',
'databases', 'requirepass', 'maxmemory','slaveof','masterauth']
args = getArgs()
conf = getConf()
content = mw.readFile(conf)
for g in gets:
if g in args:
rep = g + r'\s*([.0-9A-Za-z_& ~]+)'
val = g + ' ' + args[g]
if g == 'maxmemory':
val = g + ' ' + args[g] + "mb"
if g == 'requirepass' and args[g] == '':
content = re.sub('requirepass', '#requirepass', content)
if g == 'requirepass' and args[g] != '':
content = re.sub('#requirepass', 'requirepass', content)
content = re.sub(rep, val, content)
if g != 'requirepass':
content = re.sub(rep, val, content)
mw.writeFile(conf, content)
reload()
return mw.returnJson(True, '设置成功')
def installPreInspection():
slapd_path = '/etc/ldap/slapd.d'
if not os.path.exists(slapd_path):
return "需要手动执行:apt install -y slapd ldap-utils"
return 'ok'
if __name__ == "__main__":
func = sys.argv[1]
if func == 'status':
print(status())
elif func == 'start':
print(start())
elif func == 'stop':
print(stop())
elif func == 'restart':
print(restart())
elif func == 'reload':
print(reload())
elif func == 'initd_status':
print(initdStatus())
elif func == 'initd_install':
print(initdInstall())
elif func == 'initd_uninstall':
print(initdUinstall())
elif func == 'install_pre_inspection':
print(installPreInspection())
elif func == 'run_info':
print(runInfo())
elif func == 'conf':
print(getConf())
elif func == 'run_log':
print(runLog())
elif func == 'get_redis_conf':
print(getRedisConf())
elif func == 'submit_redis_conf':
print(submitRedisConf())
elif func == 'config_tpl':
print(configTpl())
elif func == 'read_config_tpl':
print(readConfigTpl())
else:
print('error')
+18
View File
@@ -0,0 +1,18 @@
{
"sort":4,
"ps": "LDAP轻量目录服务",
"name": "ldap",
"title": "LDAP",
"shell": "install.sh",
"versions":["1.0"],
"tip": "soft",
"install_pre_inspection":true,
"checks": "server/ldap",
"path": "server/ldap",
"display": 1,
"author": "ladp",
"date": "2025-01-28",
"home": "",
"type": 0,
"pid": "4"
}
+45
View File
@@ -0,0 +1,45 @@
#!/bin/bash
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin:/opt/homebrew/bin
export PATH
curPath=`pwd`
rootPath=$(dirname "$curPath")
rootPath=$(dirname "$rootPath")
serverPath=$(dirname "$rootPath")
sysName=`uname`
sysArch=`arch`
VERSION=$2
# https://juejin.cn/post/7309323953683480588
# dpkg-reconfigure slapd
# 该命令将在本地服务器上查找并返回在 “dc=bytedance,dc=local” 这个起点(和其下的所有子目录)下,所有 cn 属性有值的条目的详细信息
# ldapsearch -x -H ldap://localhost -b "dc=bytedance,dc=local" "(cn=*)"
Install_App()
{
echo '正在安装脚本文件...'
apt install -y slapd ldap-utils
mkdir -p $serverPath/ldap
echo "${VERSION}" > $serverPath/ldap/version.pl
echo "${VERSION}安装完成"
}
Uninstall_App()
{
apt remove -y slapd ldap-utils
rm -rf $serverPath/ldap/version.pl
rm -rf $serverPath/ldap
echo "卸载ldap成功"
}
action=$1
if [ "${1}" == 'install' ];then
Install_App
else
Uninstall_App
fi
+44
View File
@@ -0,0 +1,44 @@
#!/bin/bash
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin:/opt/homebrew/bin
export PATH
curPath=`pwd`
rootPath=$(dirname "$curPath")
rootPath=$(dirname "$rootPath")
serverPath=$(dirname "$rootPath")
sysName=`uname`
sysArch=`arch`
VERSION=$2
# https://juejin.cn/post/7309323953683480588
# dpkg-reconfigure slapd
# slappasswd 修改密码
# 该命令将在本地服务器上查找并返回在 “dc=bytedance,dc=local” 这个起点(和其下的所有子目录)下,所有 cn 属性有值的条目的详细信息
# ldapsearch -x -H ldap://localhost -b "dc=bytedance,dc=local" "(cn=*)"
Install_App()
{
echo '正在安装脚本文件...'
apt install -y slapd ldap-utils
mkdir -p $serverPath/ldap
echo "${VERSION}" > $serverPath/ldap/version.pl
echo "${VERSION}安装完成"
}
Uninstall_App()
{
rm -rf $serverPath/ldap/version.pl
echo "卸载ldap成功"
}
action=$1
if [ "${1}" == 'install' ];then
Install_App
else
Uninstall_App
fi
+116
View File
@@ -0,0 +1,116 @@
function ldapPost(method, version, args,callback){
var loadT = layer.msg('正在获取...', { icon: 16, time: 0, shade: 0.3 });
var req_data = {};
req_data['name'] = 'ldap';
req_data['func'] = method;
req_data['version'] = version;
if (typeof(args) == 'string'){
req_data['args'] = JSON.stringify(toArrayObject(args));
} else {
req_data['args'] = JSON.stringify(args);
}
$.post('/plugins/run', req_data, function(data) {
layer.close(loadT);
if (!data.status){
//错误展示10S
layer.msg(data.msg,{icon:0,time:2000,shade: [10, '#000']});
return;
}
if(typeof(callback) == 'function'){
callback(data);
}
},'json');
}
function ldapPostCallbak(method, version, args,callback){
var loadT = layer.msg('正在获取...', { icon: 16, time: 0, shade: 0.3 });
var req_data = {};
req_data['name'] = 'ldap';
req_data['func'] = method;
args['version'] = version;
if (typeof(args) == 'string'){
req_data['args'] = JSON.stringify(toArrayObject(args));
} else {
req_data['args'] = JSON.stringify(args);
}
$.post('/plugins/callback', req_data, function(data) {
layer.close(loadT);
if (!data.status){
layer.msg(data.msg,{icon:0,time:2000,shade: [0.3, '#000']});
return;
}
if(typeof(callback) == 'function'){
callback(data);
}
},'json');
}
//配置修改
function getLadpConfig(version) {
ladpPost('get_redis_conf', version,'',function(data){
// console.log(data);
var rdata = $.parseJSON(data.data);
// console.log(rdata);
var mlist = '';
for (var i = 0; i < rdata.length; i++) {
var w = '70'
if (rdata[i].name == 'error_reporting') w = '250';
var ibody = '<input style="width: ' + w + 'px;" class="bt-input-text mr5" name="' + rdata[i].name + '" value="' + rdata[i].value + '" type="text" >';
switch (rdata[i].type) {
case 0:
var selected_1 = (rdata[i].value == 1) ? 'selected' : '';
var selected_0 = (rdata[i].value == 0) ? 'selected' : '';
ibody = '<select class="bt-input-text mr5" name="' + rdata[i].name + '" style="width: ' + w + 'px;"><option value="1" ' + selected_1 + '>开启</option><option value="0" ' + selected_0 + '>关闭</option></select>'
break;
case 1:
var selected_1 = (rdata[i].value == 'On') ? 'selected' : '';
var selected_0 = (rdata[i].value == 'Off') ? 'selected' : '';
ibody = '<select class="bt-input-text mr5" name="' + rdata[i].name + '" style="width: ' + w + 'px;"><option value="On" ' + selected_1 + '>开启</option><option value="Off" ' + selected_0 + '>关闭</option></select>'
break;
}
mlist += '<p><span>' + rdata[i].name + '</span>' + ibody + ', <font>' + rdata[i].ps + '</font></p>'
}
var con = '<style>.conf_p p{margin-bottom: 2px}</style><div class="conf_p" style="margin-bottom:0">' + mlist + '\
<div style="margin-top:10px; padding-right:15px" class="text-right"><button class="btn btn-success btn-sm mr5" onclick="getRedisConfig(\'' + version + '\')">刷新</button>\
<button class="btn btn-success btn-sm" onclick="submitConf(\'' + version + '\')">保存</button></div>\
</div>'
$(".soft-man-con").html(con);
});
}
//提交配置
function submitConf(version) {
var data = {
version: version,
bind: $("input[name='bind']").val(),
'port': $("input[name='port']").val(),
'timeout': $("input[name='timeout']").val(),
maxclients: $("input[name='maxclients']").val(),
databases: $("input[name='databases']").val(),
requirepass: $("input[name='requirepass']").val(),
maxmemory: $("input[name='maxmemory']").val(),
};
redisPost('submit_ladp_conf', version, data, function(ret_data){
var rdata = $.parseJSON(ret_data.data);
layer.msg(rdata.msg, { icon: rdata.status ? 1 : 2 });
});
}
function ladpReadme(){
var readme = '<ul class="help-info-text c7">';
readme += '<li>集群创建1</li>';
readme += '</ul>';
$('.soft-man-con').html(readme);
}
+3 -1
View File
@@ -280,6 +280,7 @@ def binLog():
return mw.returnJson(False, '0')
con = con.replace('#log-bin=mysql-bin', 'log-bin=mysql-bin')
con = con.replace('#binlog_format=mixed', 'binlog_format=mixed')
mw.writeFile(conf, con)
mw.execShell('sync')
restart()
else:
@@ -294,11 +295,12 @@ def binLog():
return mw.returnJson(True, dsize)
con = con.replace('log-bin=mysql-bin', '#log-bin=mysql-bin')
con = con.replace('binlog_format=mixed', '#binlog_format=mixed')
mw.writeFile(conf, con)
mw.execShell('sync')
restart()
mw.execShell('rm -f ' + path + '/mysql-bin.*')
mw.writeFile(conf, con)
return mw.returnJson(True, '设置成功!')
def binLogList():
+2 -1
View File
@@ -1,4 +1,5 @@
{
"sort":2,
"hook":["database"],
"title":"MariaDB",
"tip":"soft",
@@ -8,7 +9,7 @@
"uninstall_pre_inspection":true,
"checks": "server/mariadb",
"path": "server/mariadb",
"versions":["10.6","10.7","10.8","10.9","10.11","11.0","11.1","11.2","11.3","11.4","11.5","11.6"],
"versions":["10.6","10.7","10.8","10.9","10.11","11.0","11.1","11.2","11.3","11.4","11.5","11.6","11.7","11.8"],
"shell":"install.sh",
"checks":"server/mariadb",
"path":"server/mariadb",
+8 -4
View File
@@ -12,15 +12,19 @@ if sys.platform != 'darwin':
os.chdir('/www/server/mdserver-web')
chdir = os.getcwd()
sys.path.append(chdir + '/class/core')
# chdir = os.getcwd()
# sys.path.append(chdir + '/class/core')
# reload(sys)
# sys.setdefaultencoding('utf-8')
web_dir = os.getcwd() + "/web"
if os.path.exists(web_dir):
sys.path.append(web_dir)
os.chdir(web_dir)
import mw
import db
import core.mw as mw
import core.db as db
class backupTools:
+1 -1
View File
@@ -13,7 +13,7 @@ sysName=`uname`
mariadbDir=${serverPath}/source/mariadb
MY_VER=10.11.10
MY_VER=10.11.11
Install_app()
{
+1 -1
View File
@@ -12,7 +12,7 @@ sysName=`uname`
mariadbDir=${serverPath}/source/mariadb
MY_VER=10.6.20
MY_VER=10.6.21
Install_app()
{
+1 -1
View File
@@ -13,7 +13,7 @@ sysName=`uname`
mariadbDir=${serverPath}/source/mariadb
MY_VER=11.4.4
MY_VER=11.4.5
Install_app()
{
+120
View File
@@ -0,0 +1,120 @@
#!/bin/bash
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin:/opt/homebrew/bin
export PATH
#https://dev.mysql.com/downloads/mysql/5.5.html#downloads
#https://dev.mysql.com/downloads/file/?id=480541
curPath=`pwd`
rootPath=$(dirname "$curPath")
rootPath=$(dirname "$rootPath")
serverPath=$(dirname "$rootPath")
sysName=`uname`
mariadbDir=${serverPath}/source/mariadb
MY_VER=11.7.2
Install_app()
{
mkdir -p ${mariadbDir}
echo '正在安装脚本文件...'
if [ "$sysName" != "Darwin" ];then
mkdir -p /var/log/mariadb
touch /var/log/mariadb/mariadb.log
fi
# ----- cpu start ------
if [ -z "${cpuCore}" ]; then
cpuCore="1"
fi
if [ -f /proc/cpuinfo ];then
cpuCore=`cat /proc/cpuinfo | grep "processor" | wc -l`
fi
MEM_INFO=$(free -m|grep Mem|awk '{printf("%.f",($2)/1024)}')
if [ "${cpuCore}" != "1" ] && [ "${MEM_INFO}" != "0" ];then
if [ "${cpuCore}" -gt "${MEM_INFO}" ];then
cpuCore="${MEM_INFO}"
fi
else
cpuCore="1"
fi
if [ "$cpuCore" -gt "2" ];then
cpuCore=`echo "$cpuCore" | awk '{printf("%.f",($1)*0.8)}'`
else
cpuCore="1"
fi
# ----- cpu end ------
# if [ ! -f ${mariadbDir}/mariadb-${MY_VER}.tar.gz ];then
# wget --no-check-certificate -O ${mariadbDir}/mariadb-${MY_VER}.tar.gz --tries=3 https://mirrors.aliyun.com/mariadb/mariadb-${MY_VER}/source/mariadb-${MY_VER}.tar.gz
# fi
# https://downloads.mariadb.org/interstitial/mariadb-10.9.1/source/mariadb-10.9.1.tar.gz
if [ ! -f ${mariadbDir}/mariadb-${MY_VER}.tar.gz ];then
wget --no-check-certificate -O ${mariadbDir}/mariadb-${MY_VER}.tar.gz --tries=3 https://archive.mariadb.org/mariadb-${MY_VER}/source/mariadb-${MY_VER}.tar.gz
fi
if [ ! -d ${mariadbDir}/mariadb-${MY_VER} ];then
cd ${mariadbDir} && tar -zxvf ${mariadbDir}/mariadb-${MY_VER}.tar.gz
fi
INSTALL_CMD=cmake
# check cmake version
CMAKE_VERSION=`cmake -version | grep version | awk '{print $3}' | awk -F '.' '{print $1}'`
if [ "$CMAKE_VERSION" -eq "2" ];then
mkdir -p /var/log/mariadb
touch /var/log/mariadb/mariadb.log
INSTALL_CMD=cmake3
fi
if [ ! -d $serverPath/mariadb ];then
cd ${mariadbDir}/mariadb-${MY_VER} && ${INSTALL_CMD} \
-DCMAKE_INSTALL_PREFIX=$serverPath/mariadb \
-DMYSQL_DATADIR=$serverPath/mariadb/data/ \
-DMYSQL_USER=mysql \
-DMYSQL_UNIX_ADDR=$serverPath/mariadb/mysql.sock \
-DWITH_MYISAM_STORAGE_ENGINE=1 \
-DWITH_INNOBASE_STORAGE_ENGINE=1 \
-DWITH_MEMORY_STORAGE_ENGINE=1 \
-DENABLED_LOCAL_INFILE=1 \
-DWITH_PARTITION_STORAGE_ENGINE=1 \
-DEXTRA_CHARSETS=all \
-DDEFAULT_CHARSET=utf8mb4 \
-DDEFAULT_COLLATION=utf8mb4_general_ci \
-DCMAKE_C_COMPILER=/usr/bin/gcc \
-DCMAKE_CXX_COMPILER=/usr/bin/g++
make -j${cpuCore} && make install && make clean
if [ -d $serverPath/mariadb ];then
echo '11.7' > $serverPath/mariadb/version.pl
echo '安装完成'
else
echo '安装失败'
echo 'install fail'>&2
exit 1
fi
fi
if [ -d ${mariadbDir}/mariadb-${MY_VER} ];then
rm -rf ${mariadbDir}/mariadb-${MY_VER}
fi
}
Uninstall_app()
{
rm -rf $serverPath/mariadb
echo '卸载完成'
}
action=$1
if [ "${1}" == 'install' ];then
Install_app
else
Uninstall_app
fi

Some files were not shown because too many files have changed in this diff Show More