Merge pull request #706 from midoks/dev

webhook插件修复
pull/710/head
Mr Chen 3 months ago committed by GitHub
commit 8ddf0168fd
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 2
      .gitignore
  2. 78
      plugins/cryptocurrency_trade/README.md
  3. 555
      plugins/cryptocurrency_trade/ccxt/public_data/data.py
  4. 12
      plugins/cryptocurrency_trade/ccxt/public_data/data.sh
  5. 19
      plugins/cryptocurrency_trade/ccxt/public_data/demo.py
  6. 0
      plugins/cryptocurrency_trade/ccxt/strategy/abs.py
  7. 352
      plugins/cryptocurrency_trade/ccxt/strategy/common.py
  8. 57
      plugins/cryptocurrency_trade/ccxt/strategy/func_test.py
  9. 440
      plugins/cryptocurrency_trade/ccxt/strategy/gate_100.py
  10. 138
      plugins/cryptocurrency_trade/ccxt/strategy/hammer_robot.py
  11. 33
      plugins/cryptocurrency_trade/ccxt/strategy/info.json
  12. 121
      plugins/cryptocurrency_trade/ccxt/strategy/macd_kdj.py
  13. 505
      plugins/cryptocurrency_trade/ccxt/strategy/momentun_trade.py
  14. 48
      plugins/cryptocurrency_trade/ccxt/strategy/notify_demo.py
  15. 294
      plugins/cryptocurrency_trade/ccxt/strategy/on_g_test.py
  16. 437
      plugins/cryptocurrency_trade/ccxt/strategy/online_macd_trade.py
  17. 273
      plugins/cryptocurrency_trade/ccxt/strategy/online_test.py
  18. 102
      plugins/cryptocurrency_trade/ccxt/strategy/rsi_robot.py
  19. 536
      plugins/cryptocurrency_trade/ccxt/strategy/vega_trade.py
  20. 128
      plugins/cryptocurrency_trade/ccxt/test/p1.py
  21. 154
      plugins/cryptocurrency_trade/ccxt/test/p2.py
  22. 61
      plugins/cryptocurrency_trade/ccxt/test/p_test.py
  23. 9
      plugins/cryptocurrency_trade/conf/create.sql
  24. 11
      plugins/cryptocurrency_trade/conf/order.sql
  25. 14
      plugins/cryptocurrency_trade/conf/sup_strategy.tpl
  26. 14
      plugins/cryptocurrency_trade/conf/sup_task.tpl
  27. 350
      plugins/cryptocurrency_trade/cryptocurrency_trade.py
  28. BIN
      plugins/cryptocurrency_trade/ico.png
  29. 26
      plugins/cryptocurrency_trade/index.html
  30. 347
      plugins/cryptocurrency_trade/index.py
  31. 36
      plugins/cryptocurrency_trade/info.json
  32. 63
      plugins/cryptocurrency_trade/install.sh
  33. 11
      plugins/cryptocurrency_trade/static/css/cryptocurrency_trade.css
  34. 11
      plugins/cryptocurrency_trade/static/css/ico.css
  35. 65
      plugins/cryptocurrency_trade/static/html/index.html
  36. 964
      plugins/cryptocurrency_trade/static/js/cryptocurrency_trade.js
  37. 21
      plugins/dztasks/LICENSE
  38. 8
      plugins/dztasks/README.md
  39. 19
      plugins/dztasks/config/dztasks.conf
  40. BIN
      plugins/dztasks/ico.png
  41. 32
      plugins/dztasks/index.html
  42. 318
      plugins/dztasks/index.py
  43. 17
      plugins/dztasks/info.json
  44. 21
      plugins/dztasks/init.d/dztasks.service.tpl
  45. 64
      plugins/dztasks/init.d/dztasks.tpl
  46. 85
      plugins/dztasks/install.sh
  47. 78
      plugins/dztasks/js/dztasks.js
  48. 2
      web/admin/dashboard/dashboard.py

2
.gitignore vendored

@ -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,6 @@ plugins/tidb
plugins/goedge-admin
plugins/goedge-node
plugins/goedge-happy
plugins/dztasks
/logs
/data

@ -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

@ -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>

@ -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')

@ -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
}

@ -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();
});

@ -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.

@ -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
```

@ -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

@ -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>

@ -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')

@ -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

@ -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

@ -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

@ -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);
}

@ -12,6 +12,8 @@ import io
import time
import base64
import json
import os
import sys
from flask import Blueprint, render_template
from flask import make_response

Loading…
Cancel
Save