├── __init__.py ├── utils ├── __init__.py ├── event │ ├── __init__.py │ └── engine.py ├── brokers.py └── utility.py ├── BNB1.png ├── ETH1.png ├── BNB0.02.png ├── BNBnew.png ├── btcusdt.png ├── order.png ├── yfiusdt.png ├── zecusdt.png ├── ETH0.003.png ├── BNB1TOETH1.png ├── eth20210726.png ├── RunUse ├── TradeRun_l36.so ├── TradeRun_w37.pyd ├── TradeRun_w38.pyd ├── setup.py └── __init__.py ├── strategies ├── base_l36.so ├── base_w37.pyd ├── base_w38.pyd ├── baseBTC_l36.so ├── baseBTC_w37.pyd ├── baseBTC_w38.pyd ├── setup.py ├── __init__.py ├── LineWithBTC.py └── LineWith.py ├── requirements.txt ├── getaway ├── __init__.py ├── send_msg.py ├── binance_ws.py ├── base_websocket.py └── binance_http.py ├── constant ├── __init__.py └── constant.py ├── Start.py ├── LICENSE ├── config.py ├── .gitignore ├── RunBTC.py └── README.md /__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /utils/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /BNB1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mn3711698/singlecoin/HEAD/BNB1.png -------------------------------------------------------------------------------- /ETH1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mn3711698/singlecoin/HEAD/ETH1.png -------------------------------------------------------------------------------- /BNB0.02.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mn3711698/singlecoin/HEAD/BNB0.02.png -------------------------------------------------------------------------------- /BNBnew.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mn3711698/singlecoin/HEAD/BNBnew.png -------------------------------------------------------------------------------- /btcusdt.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mn3711698/singlecoin/HEAD/btcusdt.png -------------------------------------------------------------------------------- /order.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mn3711698/singlecoin/HEAD/order.png -------------------------------------------------------------------------------- /yfiusdt.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mn3711698/singlecoin/HEAD/yfiusdt.png -------------------------------------------------------------------------------- /zecusdt.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mn3711698/singlecoin/HEAD/zecusdt.png -------------------------------------------------------------------------------- /ETH0.003.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mn3711698/singlecoin/HEAD/ETH0.003.png -------------------------------------------------------------------------------- /utils/event/__init__.py: -------------------------------------------------------------------------------- 1 | from .engine import Event, EventEngine, EVENT_TIMER 2 | -------------------------------------------------------------------------------- /BNB1TOETH1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mn3711698/singlecoin/HEAD/BNB1TOETH1.png -------------------------------------------------------------------------------- /eth20210726.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mn3711698/singlecoin/HEAD/eth20210726.png -------------------------------------------------------------------------------- /RunUse/TradeRun_l36.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mn3711698/singlecoin/HEAD/RunUse/TradeRun_l36.so -------------------------------------------------------------------------------- /RunUse/TradeRun_w37.pyd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mn3711698/singlecoin/HEAD/RunUse/TradeRun_w37.pyd -------------------------------------------------------------------------------- /RunUse/TradeRun_w38.pyd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mn3711698/singlecoin/HEAD/RunUse/TradeRun_w38.pyd -------------------------------------------------------------------------------- /strategies/base_l36.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mn3711698/singlecoin/HEAD/strategies/base_l36.so -------------------------------------------------------------------------------- /strategies/base_w37.pyd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mn3711698/singlecoin/HEAD/strategies/base_w37.pyd -------------------------------------------------------------------------------- /strategies/base_w38.pyd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mn3711698/singlecoin/HEAD/strategies/base_w38.pyd -------------------------------------------------------------------------------- /strategies/baseBTC_l36.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mn3711698/singlecoin/HEAD/strategies/baseBTC_l36.so -------------------------------------------------------------------------------- /strategies/baseBTC_w37.pyd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mn3711698/singlecoin/HEAD/strategies/baseBTC_w37.pyd -------------------------------------------------------------------------------- /strategies/baseBTC_w38.pyd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mn3711698/singlecoin/HEAD/strategies/baseBTC_w38.pyd -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | cython 2 | requests 3 | gunicorn 4 | gevent 5 | pandas 6 | python-socketio 7 | websocket-client 8 | apscheduler 9 | 10 | 11 | -------------------------------------------------------------------------------- /RunUse/setup.py: -------------------------------------------------------------------------------- 1 | 2 | from distutils.core import setup 3 | from Cython.Build import cythonize 4 | 5 | setup(ext_modules=cythonize(["TradeRun.py"])) 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /strategies/setup.py: -------------------------------------------------------------------------------- 1 | 2 | from distutils.core import setup 3 | from Cython.Build import cythonize 4 | 5 | setup(ext_modules=cythonize(["base.py"])) 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /getaway/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | ############################################################################## 4 | # Author:QQ173782910 5 | ############################################################################## 6 | -------------------------------------------------------------------------------- /constant/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | ############################################################################## 4 | # Author:QQ173782910 5 | ############################################################################## 6 | -------------------------------------------------------------------------------- /utils/brokers.py: -------------------------------------------------------------------------------- 1 | 2 | from utils.event.engine import EventEngine 3 | from getaway.binance_http import BinanceFutureHttp 4 | from getaway.binance_ws import BinanceDataWebsocket 5 | 6 | class Broker(object): 7 | 8 | def __init__(self, engine: EventEngine, key=None, secret=None, symbol=None): 9 | self.event_engine = engine 10 | self.binance_http = BinanceFutureHttp(key=key, secret=secret) 11 | self.binance_data_ws = BinanceDataWebsocket(broker=self) 12 | self.binance_data_ws.subscribe(symbol) 13 | self.event_engine.start() 14 | self.strategies_dict = {} 15 | 16 | def add_strategy(self, strategy_class, symbol, min_volume): 17 | self.strategies_dict[strategy_class.__name__] = strategy_class(self, symbol, min_volume) 18 | 19 | -------------------------------------------------------------------------------- /Start.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | ############################################################################## 4 | # Author:QQ173782910 5 | ############################################################################## 6 | 7 | import logging 8 | from apscheduler.schedulers.background import BlockingScheduler 9 | from RunUse import TradeRun 10 | 11 | format = '%(asctime)s - %(name)s - %(levelname)s - %(message)s' 12 | logging.basicConfig(level=logging.INFO, format=format, filename='log_print.txt') 13 | logger = logging.getLogger('print') 14 | logging.getLogger("apscheduler").setLevel(logging.WARNING) # 设置apscheduler. 15 | 16 | 17 | if __name__ == '__main__': 18 | RunTrade = TradeRun() 19 | scheduler = BlockingScheduler() # 定时的任务. 20 | scheduler.add_job(RunTrade.get_kline_data, trigger='cron', second='*/2') # 主计算k线 21 | scheduler.add_job(RunTrade.get_open_orders, trigger='cron', second='*/2') # 未成交单 22 | scheduler.add_job(RunTrade.get_position, trigger='cron', second='*/1') # 仓位 23 | scheduler.start() -------------------------------------------------------------------------------- /constant/constant.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | ############################################################################## 4 | # Author:QQ173782910 5 | ############################################################################## 6 | 7 | 8 | EVENT_HOUR_KLINE = "ENENT_HOUR_KLINE" #K线事件 9 | EVENT_DAY_KLINE = "EVENT_DAY_KLINE" 10 | EVENT_KLINE = "EVENT_KLINE" 11 | EVENT_MINUTE_KLINE = "EVENT_MINUTE_KLINE" 12 | EVENT_TICKER = "EVENT_TICKER" #Ticker 事件 13 | EVENT_DEPTH = "EVENT_DEPTH" #depth 14 | EVENT_POS = "EVENT_POS" #仓位事件 15 | EVENT_OPEN_ORDERS = "EVENT_OPEN_ORDERS" #挂单order 16 | EVENT_TIMER = "EVENT_TIMER" #定时器事件,默认是1秒钟推送一次,可以用来做定时任务 17 | EVENT_ACCOUNT = "EVENT_ACCOUNT" 18 | EVENT_TRADE = "EVENT_TRADE" 19 | EVENT_KLINE_5m = "EVENT_KLINE_5m" #K线事件 20 | EVENT_KLINE_15m = "EVENT_KLINE_15m" #K线事件 21 | EVENT_KLINE_30m = "EVENT_KLINE_30m" #K线事件 22 | EVENT_KLINE_1h = "EVENT_KLINE_1h" #K线事件 23 | EVENT_KLINE_2h = "EVENT_KLINE_2h" #K线事件 24 | EVENT_KLINE_4h = "EVENT_KLINE_4h" #K线事件 25 | EVENT_KLINE_1d = "EVENT_KLINE_1d" #K线事件 26 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 mn3711698 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /strategies/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | ############################################################################## 4 | # Author:QQ173782910 5 | ############################################################################## 6 | # linux支持python3.6 windows支持64位python3.8,python3.7 7 | import platform 8 | 9 | if platform.system() == 'Windows': 10 | if '3.8' in platform.python_version(): 11 | try: 12 | from .base import Base 13 | 14 | except Exception as e: 15 | raise ValueError("请将本目前下的base_w38重命名为base替换原来的base") 16 | elif '3.7' in platform.python_version(): 17 | try: 18 | from .base import Base 19 | 20 | except Exception as e: 21 | raise ValueError("请将本目前下的base_w37重命名为base替换原来的base") 22 | else: 23 | raise ValueError("python版本未提供支持") 24 | elif platform.system() == 'Linux': 25 | if '3.6' in platform.python_version(): 26 | try: 27 | from .base import Base 28 | 29 | except Exception as e: 30 | raise ValueError("请将本目前下的base_l36.so重命名为base.so替换原来的base.so") 31 | else: 32 | raise ValueError("python版本未提供支持") 33 | else: 34 | raise ValueError("操作系统未提供支持") 35 | -------------------------------------------------------------------------------- /RunUse/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | ############################################################################## 4 | # Author:QQ173782910 5 | ############################################################################## 6 | # linux支持python3.6 windows支持64位python3.8,python3.7 7 | import platform 8 | 9 | if platform.system() == 'Windows': 10 | if '3.8' in platform.python_version(): 11 | try: 12 | from .TradeRun import TradeRun 13 | 14 | except Exception as e: 15 | raise ValueError("请将本目前下的TradeRun_w38重命名为TradeRun替换原来的TradeRun") 16 | 17 | elif '3.7' in platform.python_version(): 18 | try: 19 | from .TradeRun import TradeRun 20 | 21 | except Exception as e: 22 | raise ValueError("请将本目前下的TradeRun_w37重命名为TradeRun替换原来的TradeRun") 23 | else: 24 | raise ValueError("python版本未提供支持") 25 | elif platform.system() == 'Linux': 26 | if '3.6' in platform.python_version(): 27 | try: 28 | from .TradeRun import TradeRun 29 | 30 | except Exception as e: 31 | raise ValueError("请将本目前下的TradeRun_l36.so重命名为TradeRun.so替换原来的TradeRun.so") 32 | else: 33 | raise ValueError("python版本未提供支持") 34 | else: 35 | raise ValueError("操作系统未提供支持") 36 | -------------------------------------------------------------------------------- /config.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | ############################################################################## 3 | # Author:QQ173782910 4 | ############################################################################## 5 | 6 | # 注意: 7 | # 持仓方向为单向,不会设置杠杆 8 | # 下边的dingding_token,wx_openid为空的话是不会发送钉钉消息和公众号消息 9 | 10 | version_flag = '20210903' 11 | 12 | key = "" # 币安API的key 13 | secret = "" # 币安API的secret 14 | symbol = "BNBUSDT" # 交易对,目前保证支持BNBUSDT,ETHUSDT这两个 15 | # trading_size BTCUSDT,YFIUSDT最小为0.001 16 | trading_size = 0.02 # 下单量,至少要比币对最小值要大,注意控制风险 eth最小为0.003,BNB:0.02 还要注意价值要大于5u 17 | 18 | dingding_token = "" # 钉钉webhook的access_token 19 | wx_openid = "" # 关注简道斋后发送openid得到的那一串字符就是这个 20 | 21 | tactics_flag = 1 # 此为机器人执行策略计算无信号是否发送钉钉消息,约15分钟发送一次,1为发送,不发送请留空或其他值 22 | 23 | orders_seconds = 0 # 预留 24 | 25 | long_stoploss = 4.95 / 100 # eth,bnb,止损百分比 持仓价涨跌这个值止损 26 | long_takeprofit = 3.72 / 100 # etn,止盈百分比 持仓价涨跌这个值止盈 27 | long_line_poor = 0.979 # 计算参数bnb:15min:0.626/0.38,0.04,5min:0.36,eth:5.2,其他未知 28 | long_line_poor_stop = 0.018 # 计算参数bnb:15min:0.5/0.2/0.05,5min:0.4,eth:15min:6.22,其他未知 29 | 30 | short_stoploss = 1.23 / 100 # eth,bnb,止损百分比 持仓价涨跌这个值止损 31 | short_takeprofit = 1.71 / 100 # etn,止盈百分比 持仓价涨跌这个值止盈 32 | short_line_poor = 0.13 # 计算参数bnb:15min:0.626/0.38,0.04,5min:0.36,eth:5.2,其他未知 ?0.138 33 | short_line_poor_stop = 0.05 # 计算参数bnb:15min:0.5/0.2/0.05,5min:0.4,eth:15min:6.22,其他未知 34 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[co] 4 | *$py.class 5 | 6 | # C extensions 7 | #*.so 8 | #*.pyd 9 | 10 | base.py 11 | TradeRun.py 12 | 13 | # Distribution / packaging 14 | .Python 15 | build/ 16 | develop-eggs/ 17 | dist/ 18 | downloads/ 19 | eggs/ 20 | .eggs/ 21 | lib/ 22 | lib64/ 23 | parts/ 24 | sdist/ 25 | var/ 26 | wheels/ 27 | pip-wheel-metadata/ 28 | share/python-wheels/ 29 | *.egg-info/ 30 | .installed.cfg 31 | *.egg 32 | MANIFEST 33 | 34 | # PyInstaller 35 | # Usually these files are written by a python script from a template 36 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 37 | *.manifest 38 | *.spec 39 | 40 | # Installer logs 41 | pip-log.txt 42 | pip-delete-this-directory.txt 43 | 44 | # Unit test / coverage reports 45 | htmlcov/ 46 | .tox/ 47 | .nox/ 48 | .coverage 49 | .coverage.* 50 | .cache 51 | nosetests.xml 52 | coverage.xml 53 | *.cover 54 | *.py,cover 55 | .hypothesis/ 56 | .pytest_cache/ 57 | 58 | # Translations 59 | *.mo 60 | *.pot 61 | 62 | # Django stuff: 63 | *.log 64 | local_settings.py 65 | db.sqlite3 66 | db.sqlite3-journal 67 | 68 | # Flask stuff: 69 | instance/ 70 | .webassets-cache 71 | 72 | # Scrapy stuff: 73 | .scrapy 74 | 75 | # Sphinx documentation 76 | docs/_build/ 77 | 78 | # PyBuilder 79 | target/ 80 | 81 | # Jupyter Notebook 82 | .ipynb_checkpoints 83 | 84 | # IPython 85 | profile_default/ 86 | ipython_config.py 87 | 88 | # pyenv 89 | .python-version 90 | 91 | # pipenv 92 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. 93 | # However, in case of collaboration, if having platform-specific dependencies or dependencies 94 | # having no cross-platform support, pipenv may install dependencies that don't work, or not 95 | # install all needed dependencies. 96 | #Pipfile.lock 97 | 98 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow 99 | __pypackages__/ 100 | 101 | # Celery stuff 102 | celerybeat-schedule 103 | celerybeat.pid 104 | 105 | # SageMath parsed files 106 | *.sage.py 107 | 108 | # Environments 109 | .env 110 | .venv 111 | env/ 112 | venv/ 113 | ENV/ 114 | env.bak/ 115 | venv.bak/ 116 | 117 | # Spyder project settings 118 | .spyderproject 119 | .spyproject 120 | 121 | # Rope project settings 122 | .ropeproject 123 | 124 | # mkdocs documentation 125 | /site 126 | 127 | # mypy 128 | .mypy_cache/ 129 | .dmypy.json 130 | dmypy.json 131 | 132 | # Pyre type checker 133 | .pyre/ 134 | -------------------------------------------------------------------------------- /getaway/send_msg.py: -------------------------------------------------------------------------------- 1 | import json 2 | import requests 3 | import traceback 4 | import time 5 | from config import dingding_token, wx_openid, symbol 6 | 7 | 8 | def dingding(msg, symbols=''): 9 | if dingding_token == '': 10 | return 11 | 12 | if symbols == '': 13 | symbols = symbol 14 | 15 | webhook = "https://oapi.dingtalk.com/robot/send?access_token=%s"%dingding_token 16 | headers = {"Content-Type": "application/json", "Charset": "UTF-8"} 17 | message = { 18 | "msgtype": "text", 19 | "text": {"content": "%s提醒%s:%s"%(getToday(9), symbols, msg)}, 20 | "at": {"isAtall": False} 21 | } 22 | try: 23 | message_json = json.dumps(message) 24 | _http = requests.Session() 25 | info = _http.post(url=webhook, data=message_json.encode('utf-8'), headers=headers) 26 | except: 27 | bugcode(traceback, ctype='singlecoin_dingding') 28 | 29 | 30 | def getToday(format=3): 31 | """返回今天的日期字串""" 32 | t = time.time() 33 | date_ary = time.localtime(t) 34 | if format == 1: 35 | x = time.strftime("%Y%m%d", date_ary) 36 | elif format == 2: 37 | x = time.strftime("%H:%M", date_ary) 38 | elif format == 3: 39 | x = time.strftime("%Y/%m/%d", date_ary) 40 | elif format == 4: 41 | x = time.strftime("%Y/%m/%d %H:%M", date_ary) 42 | elif format == 5: 43 | x = time.strftime("%y%m%d", date_ary) 44 | elif format == 6: 45 | x = time.strftime("%Y-%m-%d", date_ary) 46 | elif format == 7: 47 | x = time.strftime("%Y/%m/%d %H:%M:%S", date_ary) 48 | elif format == 8: 49 | x = time.strftime("%Y-%m-%d %H:%M", date_ary) 50 | elif format == 9: 51 | x = time.strftime("%Y-%m-%d %H:%M:%S", date_ary) 52 | elif format == 10: 53 | x = time.strftime("%Y年%m月%d日 %H:%M", date_ary) 54 | else: 55 | x = time.strftime("%Y-%m-%d %H:%M:%S", date_ary) 56 | return x 57 | 58 | 59 | def bugcode(traceback, ctype = 'ok'): 60 | 61 | if ctype != 'ok': 62 | errInf = str(traceback.format_exc()) 63 | else: 64 | errInf = traceback 65 | 66 | gUrl = 'https://link.yjyzj.cn/api' 67 | pdata = {'viewid': 'home', 'part': 'collect', 68 | 'ctype': ctype, 'errInf': errInf,'title': 'singlecoin'} 69 | try: 70 | _http = requests.Session() 71 | r = _http.post(gUrl, data=pdata) 72 | except: 73 | pass 74 | 75 | 76 | def wx_send_msg(first, tradeType, curAmount, remark): 77 | if wx_openid == '': 78 | return 79 | data = {"sendId": wx_openid, 80 | "first": first, # 第一行的内容 81 | "tradeType": tradeType, # 交易类型的内容 82 | "curAmount": curAmount, # 交易金额的内容 83 | "remark": remark, # 备注的内容 84 | } 85 | 86 | gUrl = 'https://yjyzj.cn/stockwx' 87 | try: 88 | _http = requests.Session() 89 | r = _http.post(gUrl, data=data) 90 | except: 91 | bugcode(traceback, ctype='singlecoin_wx_send_msg') -------------------------------------------------------------------------------- /utils/utility.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | ############################################################################## 4 | # Author:QQ173782910 5 | ############################################################################## 6 | 7 | 8 | import json 9 | from pathlib import Path 10 | from decimal import Decimal 11 | 12 | 13 | def _get_trader_dir(temp_name: str): 14 | """ 15 | Get path where trader is running in. 16 | """ 17 | cwd = Path.cwd() 18 | temp_path = cwd.joinpath(temp_name) 19 | 20 | # If .vntrader folder exists in current working directory, 21 | # then use it as running path. 22 | if temp_path.exists(): 23 | return cwd, temp_path 24 | 25 | # Create .vntrader folder under home path if not exist. 26 | if not temp_path.exists(): 27 | temp_path.mkdir() 28 | 29 | return cwd, temp_path 30 | 31 | 32 | TRADER_DIR, TEMP_DIR = _get_trader_dir("") 33 | 34 | 35 | def get_file_path(filename: str): 36 | """ 37 | Get path for temp file with filename. 38 | """ 39 | return TEMP_DIR.joinpath(filename) 40 | 41 | 42 | def get_folder_path(folder_name: str): 43 | """ 44 | Get path for temp folder with folder name. 45 | """ 46 | folder_path = TEMP_DIR.joinpath(folder_name) 47 | if not folder_path.exists(): 48 | folder_path.mkdir() 49 | return folder_path 50 | 51 | def load_json(filename: str): 52 | """ 53 | Load data from json file in temp path. 54 | """ 55 | filepath = get_file_path(filename) 56 | 57 | if filepath.exists(): 58 | # with open(filepath, mode="r", encoding="UTF-8") as f: 59 | try: 60 | with open(filepath, mode="r", encoding="UTF-8") as f: 61 | data = json.load(f) 62 | except: 63 | data = {} 64 | return data 65 | else: 66 | save_json(filename, {}) 67 | return {} 68 | 69 | 70 | def save_json(filename: str, data: dict): 71 | """ 72 | Save data into json file in temp path. 73 | """ 74 | filepath = get_file_path(filename) 75 | with open(filepath, mode="w+", encoding="UTF-8") as f: 76 | json.dump( 77 | data, 78 | f, 79 | indent=4, 80 | ensure_ascii=False 81 | ) 82 | 83 | 84 | 85 | 86 | def round_to(value: float, target: float) -> float: 87 | """ 88 | Round price to price tick value. 89 | """ 90 | value = Decimal(str(value)) 91 | target = Decimal(str(target)) 92 | rounded = float(int(round(value / target)) * target) 93 | return rounded 94 | 95 | if __name__ == '__main__': 96 | file_name = "BigSmallRateStrategy" #if BigSmallRateStrategy else self.__class__.__name__ #  用来记录数据用的. 97 | # file_name = "BollMacdStrategy" 98 | get = get_file_path(file_name) 99 | print(get) 100 | load = load_json(file_name) 101 | print(load) 102 | # self.json_data = load_json(self.file_name) -------------------------------------------------------------------------------- /getaway/binance_ws.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | ############################################################################## 4 | # Author:QQ173782910 5 | ############################################################################## 6 | 7 | import json 8 | from datetime import datetime 9 | from getaway.base_websocket import BaseWebsocket 10 | from utils.event.engine import EventEngine, Event 11 | from constant.constant import EVENT_TICKER, EVENT_DEPTH 12 | 13 | class BinanceDataWebsocket(BaseWebsocket): 14 | def __init__(self, broker=None, ping_interval=20): 15 | 16 | self.broker = broker 17 | host = "wss://fstream.binance.com/stream?streams=" 18 | super(BinanceDataWebsocket, self).__init__(host=host,ping_interval=ping_interval) 19 | self.symbols = set() 20 | 21 | def on_msg(self, data: str): 22 | json_msg = json.loads(data) 23 | stream = json_msg["stream"] 24 | symbol, channel = stream.split("@") 25 | data = json_msg["data"] 26 | if channel == 'ticker': 27 | if self.broker: 28 | engine: EventEngine = self.broker.event_engine 29 | ticker = {"volume": float(data['v']), 30 | "open_price":float(data['o']), 31 | "high_price": float(data['h']), 32 | "low_price": float(data['l']), 33 | "last_price": float(data['c']), 34 | "datetime": data['E'], 35 | "symbol": symbol.upper() 36 | } 37 | event = Event(EVENT_TICKER, {"ticker": ticker}) 38 | engine.put(event) 39 | 40 | elif channel == 'depth5': 41 | if self.broker: 42 | engine: EventEngine = self.broker.event_engine 43 | depth = { 44 | "last_ask": float(data['a'][0][0]), 45 | "ask2": float(data['a'][1][0]), 46 | "ask3": float(data['a'][2][0]), 47 | "last_bid": float(data['b'][0][0]), 48 | "bid2": float(data['b'][1][0]), 49 | "bid3": float(data['b'][2][0]), 50 | "datetime": datetime.fromtimestamp(float(data['E']) / 1000), 51 | "symbol": symbol.upper() 52 | } 53 | 54 | event = Event(EVENT_DEPTH, {"depth": depth}) 55 | engine.put(event) 56 | 57 | else: 58 | print(channel,data) 59 | 60 | 61 | def on_error(self, exception_type: type, exception_value: Exception, tb): 62 | print("on error") 63 | 64 | def subscribe(self, symbol): 65 | 66 | self.symbols.add(symbol) 67 | if self._active: 68 | self.stop() 69 | self.join() 70 | channels = [] 71 | for symbol in self.symbols: 72 | channels.append(symbol.lower()+"@ticker") 73 | channels.append(symbol.lower() + "@depth5") 74 | 75 | self.host += '/'.join(channels) 76 | self.start() 77 | 78 | 79 | if __name__ == '__main__': 80 | ws = BinanceDataWebsocket() 81 | ws.subscribe('bnbusdt') 82 | 83 | -------------------------------------------------------------------------------- /RunBTC.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | ############################################################################## 4 | # Author:QQ173782910 5 | ############################################################################## 6 | 7 | import logging 8 | from apscheduler.schedulers.background import BlockingScheduler 9 | from utils.brokers import Broker 10 | from getaway.binance_http import Interval, BinanceFutureHttp 11 | from constant.constant import (EVENT_POS, EVENT_KLINE) 12 | from utils.event import EventEngine, Event 13 | from strategies.LineWithBTC import LineWithBTC 14 | from config import key, secret, trading_size 15 | 16 | format = '%(asctime)s - %(name)s - %(levelname)s - %(message)s' 17 | logging.basicConfig(level=logging.INFO, format=format, filename='log_print.txt') 18 | logger = logging.getLogger('print') 19 | logging.getLogger("apscheduler").setLevel(logging.WARNING) # 设置apscheduler. 20 | 21 | 22 | class TradeRun: 23 | 24 | def __init__(self): 25 | self.trading_size = trading_size 26 | self.min_volume = 0.001 27 | self.key = key 28 | self.secret = secret 29 | self.symbol = "BTCUSDT" # "YFIUSDT" 白嫖只提供这两个,单币运行 30 | self.kline_time = 0 31 | self.engine = EventEngine() 32 | self.broker = Broker(self.engine, self.key, secret=self.secret, symbol=self.symbol) 33 | self.initialization_data() 34 | self.broker.add_strategy(LineWithBTC, symbol=self.symbol, min_volume=self.min_volume) 35 | 36 | def initialization_data(self): 37 | 38 | binance_http = BinanceFutureHttp(key=self.key, secret=self.secret) 39 | einfo = binance_http.exchangeInfo() 40 | if isinstance(einfo, dict): 41 | esymbols = einfo['symbols'] 42 | for i in esymbols: 43 | if i['symbol'] == self.symbol: 44 | for j in i['filters']: 45 | if j['filterType'] == 'LOT_SIZE': 46 | minQty = float(j['minQty']) 47 | if minQty > self.trading_size: 48 | print('config.py里的trading_size太小') 49 | raise ValueError("config.py里的trading_size太小") 50 | self.min_volume = minQty 51 | 52 | def get_kline_data(self): 53 | 54 | data = self.broker.binance_http.get_kline(symbol=self.symbol, interval=Interval.MINUTE_5, limit=100) 55 | if len(data): 56 | kline_time = data[-1][0] 57 | if kline_time != self.kline_time: 58 | event = Event(EVENT_KLINE, {'symbol': self.symbol, "data": data, '_flag': ''}) 59 | self.broker.event_engine.put(event) 60 | self.kline_time = kline_time 61 | 62 | def get_position(self): 63 | if self.symbol != '': 64 | info = self.broker.binance_http.get_position_info() 65 | if isinstance(info, list): 66 | for item in info: 67 | symbol = item["symbol"] 68 | if self.symbol == symbol: 69 | event = Event(EVENT_POS, {"symbol": symbol, "pos": item}) 70 | self.broker.event_engine.put(event) 71 | 72 | 73 | if __name__ == '__main__': 74 | minute_str = '0,5,10,15,20,25,30,35,40,45,50,55' 75 | RunTrade = TradeRun() 76 | scheduler = BlockingScheduler() # 定时的任务. 77 | scheduler.add_job(RunTrade.get_kline_data, trigger='cron', id='TradeRunk', minute=minute_str, second='3') 78 | scheduler.add_job(RunTrade.get_position, trigger='cron', id='TradeRunp', second='*/1') # 仓位 79 | scheduler.start() -------------------------------------------------------------------------------- /utils/event/engine.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | ############################################################################## 4 | # Author:QQ173782910 5 | ############################################################################## 6 | 7 | 8 | from collections import defaultdict 9 | from queue import Empty, Queue 10 | from threading import Thread 11 | from time import sleep 12 | from typing import Any, Callable 13 | from constant.constant import EVENT_TIMER 14 | 15 | 16 | 17 | class Event: 18 | """ 19 | Event object consists of a type string which is used 20 | by event engine for distributing event, and a data 21 | object which contains the real data. 22 | """ 23 | 24 | def __init__(self, type: str, data: Any = None): 25 | """""" 26 | self.type = type 27 | self.data = data 28 | 29 | 30 | # Defines handler function to be used in event engine. 31 | HandlerType = Callable[[Event], None] 32 | 33 | 34 | class EventEngine: 35 | """ 36 | Event engine distributes event object based on its type 37 | to those handlers registered. 38 | 39 | It also generates timer event by every interval seconds, 40 | which can be used for timing purpose. 41 | """ 42 | 43 | def __init__(self, interval: int = 1): 44 | """ 45 | Timer event is generated every 1 second by default, if 46 | interval not specified. 47 | """ 48 | self._interval = interval 49 | self._queue = Queue() 50 | self._active = False 51 | self._thread = Thread(target=self._run) 52 | self._timer = Thread(target=self._run_timer) 53 | self._handlers = defaultdict(list) 54 | self._general_handlers = [] 55 | 56 | def _run(self): 57 | """ 58 | Get event from queue and then process it. 59 | """ 60 | while self._active: 61 | try: 62 | event = self._queue.get(block=True, timeout=1) 63 | self._process(event) 64 | except Empty: 65 | pass 66 | 67 | def _process(self, event: Event): 68 | """ 69 | First ditribute event to those handlers registered listening 70 | to this type. 71 | 72 | Then distrubute event to those general handlers which listens 73 | to all types. 74 | """ 75 | if event.type in self._handlers: 76 | [handler(event) for handler in self._handlers[event.type]] 77 | 78 | if self._general_handlers: 79 | [handler(event) for handler in self._general_handlers] 80 | 81 | def _run_timer(self): 82 | """ 83 | Sleep by interval second(s) and then generate a timer event. 84 | """ 85 | while self._active: 86 | sleep(self._interval) 87 | event = Event(EVENT_TIMER) 88 | self.put(event) 89 | 90 | def start(self): 91 | """ 92 | Start event engine to process events and generate timer events. 93 | """ 94 | self._active = True 95 | self._thread.start() 96 | self._timer.start() 97 | 98 | def stop(self): 99 | """ 100 | Stop event engine. 101 | """ 102 | self._active = False 103 | self._timer.join() 104 | self._thread.join() 105 | 106 | def put(self, event: Event): 107 | """ 108 | Put an event object into event queue. 109 | """ 110 | self._queue.put(event) 111 | 112 | def register(self, type: str, handler: HandlerType): 113 | """ 114 | Register a new handler function for a specific event type. Every 115 | function can only be registered once for each event type. 116 | """ 117 | handler_list = self._handlers[type] 118 | if handler not in handler_list: 119 | handler_list.append(handler) 120 | 121 | def unregister(self, type: str, handler: HandlerType): 122 | """ 123 | Unregister an existing handler function from event engine. 124 | """ 125 | handler_list = self._handlers[type] 126 | 127 | if handler in handler_list: 128 | handler_list.remove(handler) 129 | 130 | if not handler_list: 131 | self._handlers.pop(type) 132 | 133 | def register_general(self, handler: HandlerType): 134 | """ 135 | Register a new handler function for all event types. Every 136 | function can only be registered once for each event type. 137 | """ 138 | if handler not in self._general_handlers: 139 | self._general_handlers.append(handler) 140 | 141 | def unregister_general(self, handler: HandlerType): 142 | """ 143 | Unregister an existing general handler function. 144 | """ 145 | if handler in self._general_handlers: 146 | self._general_handlers.remove(handler) 147 | -------------------------------------------------------------------------------- /strategies/LineWithBTC.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | ############################################################################## 3 | # Author:QQ173782910 4 | ############################################################################## 5 | 6 | from datetime import datetime 7 | from strategies.baseBTC import BaseBTC 8 | from getaway.send_msg import dingding, wx_send_msg 9 | 10 | 11 | class LineWithBTC(BaseBTC): 12 | 13 | def on_pos_data(self, pos_dict): 14 | # 先判断是否有仓位,如果是多头的仓位, 然后检查下是多头还是空头,设置相应的止损的价格.. 15 | current_pos = float(pos_dict['positionAmt']) 16 | self.unRealizedProfit = float(pos_dict['unRealizedProfit']) 17 | entryPrice = float(pos_dict['entryPrice']) 18 | winPrice = entryPrice * 1.01 # 这个1.01是可修改的止盈参数,持仓价乘以1.01的值,当这个值大于当前价就止盈。 19 | if self.enter_price == 0 or self.enter_price != entryPrice: 20 | self.enter_price = entryPrice 21 | self.win_price = winPrice 22 | if self.pos != 0: 23 | if self.unRealizedProfit > 0: 24 | self.maxunRealizedProfit = max(self.maxunRealizedProfit, self.unRealizedProfit) 25 | elif self.unRealizedProfit < 0: 26 | self.lowProfit = min(self.lowProfit, self.unRealizedProfit) 27 | 28 | if self.pos != current_pos: # 检查仓位是否是一一样的. 29 | 30 | if current_pos == 0: 31 | dingding(f"仓位检查:{self.symbol},交易所帐户仓位为0,无持仓,系统仓位为:{self.pos},重置为0", symbols=self.symbol) 32 | self.pos = 0 33 | self.sync_data() 34 | return 35 | elif current_pos != 0: 36 | dingding(f"仓位检查:{self.symbol},交易所帐户仓位为:{current_pos},有持仓,系统仓位为:{self.pos},重置为:{current_pos}", symbols=self.symbol) 37 | self.pos = current_pos 38 | self.sync_data() 39 | return 40 | 41 | def on_ticker_data(self, ticker): 42 | self.ticker_data(ticker) 43 | 44 | def ticker_data(self, ticker): 45 | 46 | if self.symbol == ticker['symbol']: 47 | last_price = float(ticker['last_price']) # 最新的价格. 48 | self.last_price = last_price 49 | 50 | if self.pos != 0: 51 | if self.high_price > 0: 52 | self.high_price = max(self.high_price, self.last_price) 53 | if self.low_price > 0: 54 | self.low_price = min(self.low_price, self.last_price) 55 | 56 | if self.pos == 0: # 无持仓 57 | 58 | if self.order_flag > self.last_price > 0: 59 | # 因为有一个止盈,在策略计算没有平仓信号的情况下平仓了,那遇到更低价的机会也不能错过 60 | self.pos = self.round_to(self.trading_size, self.min_volume) 61 | enter_price = self.ask 62 | res_buy = self.buy(enter_price, abs(self.pos), mark=True) 63 | self.enter_price = enter_price 64 | self.high_price = enter_price 65 | self.low_price = enter_price 66 | self.maxunRealizedProfit = 0 67 | self.unRealizedProfit = 0 68 | self.lowProfit = 0 69 | self.pos_update_time = datetime.now() 70 | self.sync_data() 71 | HYJ_jd_first = f"回补仓位,交易对:{self.symbol},仓位:{self.pos}" 72 | HYJ_jd_tradeType = "开多" 73 | HYJ_jd_curAmount = f"{enter_price}" 74 | HYJ_jd_remark = f"回补仓位,留意仓位" 75 | self.dingding(f"开多交易所返回:{res_buy}", symbols=self.symbol) 76 | self.wx_send_msg(HYJ_jd_first, HYJ_jd_tradeType, HYJ_jd_curAmount, HYJ_jd_remark) 77 | 78 | elif self.pos > 0: # 多单持仓 79 | 80 | enter_price = self.bid2 # +1 81 | Profit = self.round_to((enter_price - self.enter_price) * abs(self.pos), self.min_price) 82 | if last_price > self.win_price > 0: # 策略未出来平仓信号,有利润要止盈 83 | res_sell = self.sell(enter_price, abs(self.pos), mark=True) 84 | HYJ_jd_first = "止盈平多:交易对:%s,最大亏损:%s,最大利润:%s,当前利润:%s,仓位:%s" % ( 85 | self.symbol, self.lowProfit, self.maxunRealizedProfit, self.unRealizedProfit, self.pos) 86 | self.pos = 0 87 | HYJ_jd_tradeType = "平多" 88 | HYJ_jd_curAmount = "%s" % enter_price 89 | HYJ_jd_remark = "止盈平多:%s,最新价:%s,最高价:%s,最低价:%s" % ( 90 | Profit, self.last_price, self.high_price, self.low_price) 91 | self.enter_price = 0 92 | self.high_price = 0 93 | self.low_price = 0 94 | self.maxunRealizedProfit = 0 95 | self.unRealizedProfit = 0 96 | self.lowProfit = 0 97 | self.sync_data() 98 | self.dingding(f"止盈平多,交易所返回:{res_sell}", symbols=self.symbol) 99 | self.wx_send_msg(HYJ_jd_first, HYJ_jd_tradeType, HYJ_jd_curAmount, HYJ_jd_remark) -------------------------------------------------------------------------------- /getaway/base_websocket.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | ############################################################################## 4 | #Author:QQ173782910 5 | ############################################################################## 6 | 7 | import json 8 | import sys 9 | import traceback 10 | import socket 11 | from datetime import datetime 12 | from time import sleep 13 | from threading import Lock,Thread 14 | import websocket 15 | 16 | class BaseWebsocket(object): 17 | def __init__(self,host=None, ping_interval= 10): 18 | self.host = host 19 | self.ping_interval = ping_interval 20 | 21 | self._ws_lock = Lock() 22 | self._ws = None 23 | 24 | self._worker_thread = None 25 | self._ping_thread = None 26 | self._active = False 27 | 28 | # debug需要.. 29 | self._last_sent_text = None 30 | self._last_received_text = None 31 | 32 | def start(self): 33 | """q启用客户端,连接成功之后会调用on——open这个方法。之后才调用向服务器发送消息的方法""" 34 | self._active = True 35 | self._worker_thread = Thread(target=self._run) #调用保持运行函数,之前已经定义self.woruthread为None 36 | self._worker_thread.start() 37 | 38 | self._ping_thread = Thread(target=self._run_ping) 39 | self._ping_thread.start() 40 | 41 | def stop(self): 42 | self._active = False 43 | self._disconnect() 44 | 45 | def join(self): 46 | self._ping_thread.join() 47 | self._worker_thread.join() 48 | 49 | def send_msg(self, msg:dict): 50 | text = json.dumps(msg) 51 | self._record_last_sent_text(text) 52 | return self._send_text(text) 53 | 54 | def _send_text(self, text:str): 55 | ws = self._ws 56 | if ws: 57 | ws.send(text, opcode = websocket.ABNF.OPCODE_TEXT) 58 | 59 | def _ensure_connection(self): 60 | """""" 61 | triggered = False 62 | with self._ws_lock: 63 | if self._ws is None: 64 | self._ws = websocket.create_connection(self.host) 65 | 66 | triggered = True 67 | if triggered: 68 | self.on_open() 69 | 70 | def _disconnect(self): 71 | """ 72 | """ 73 | triggered = False 74 | with self._ws_lock: 75 | if self._ws: 76 | ws: websocket.WebSocket = self._ws 77 | self._ws = None 78 | 79 | triggered = True 80 | if triggered: 81 | ws.close() 82 | self.on_close() 83 | 84 | 85 | def _run(self): 86 | """ 87 | 保持运行,知道stop方法调用. 88 | """ 89 | try: 90 | while self._active: 91 | try: 92 | self._ensure_connection() 93 | ws = self._ws 94 | if ws: 95 | text = ws.recv() 96 | 97 | # ws object is closed when recv function is blocking 98 | if not text: 99 | self._disconnect() 100 | continue 101 | 102 | self._record_last_received_text(text) 103 | 104 | self.on_msg(text) 105 | # ws is closed before recv function is called 106 | # For socket.error, see Issue #1608 107 | except (websocket.WebSocketConnectionClosedException, socket.error): 108 | self._disconnect() 109 | 110 | # other internal exception raised in on_msg 111 | except: # noqa 112 | et, ev, tb = sys.exc_info() 113 | self.on_error(et, ev, tb) 114 | self._disconnect() # 115 | 116 | except: # noqa 117 | et, ev, tb = sys.exc_info() 118 | self.on_error(et, ev, tb) 119 | 120 | self._disconnect() 121 | 122 | 123 | def _run_ping(self): 124 | """""" 125 | while self._active: 126 | try: 127 | self._ping() 128 | except: # noqa 129 | et, ev, tb = sys.exc_info() 130 | self.on_error(et, ev, tb) 131 | sleep(1) 132 | 133 | for i in range(self.ping_interval): 134 | if not self._active: 135 | break 136 | sleep(1) 137 | 138 | 139 | def _ping(self): 140 | """""" 141 | ws = self._ws 142 | if ws: 143 | ws.send("ping", websocket.ABNF.OPCODE_PING) 144 | 145 | 146 | def on_open(self): 147 | """on open """ 148 | print("websocket open..") 149 | 150 | 151 | def on_close(self): 152 | """ 153 | on close websocket 154 | """ 155 | print("websocket close......") 156 | 157 | 158 | def on_msg(self, data: str): 159 | """call when the msg arrive.""" 160 | pass 161 | 162 | def on_error(self, exception_type: type, exception_value: Exception, tb): 163 | """ 164 | Callback when exception raised. 165 | """ 166 | sys.stderr.write( 167 | self.exception_detail(exception_type, exception_value, tb) 168 | ) 169 | 170 | return sys.excepthook(exception_type, exception_value, tb) 171 | 172 | def exception_detail( 173 | self, exception_type: type, exception_value: Exception, tb 174 | ): 175 | """ 176 | Print detailed exception information. 177 | """ 178 | text = "[{}]: Unhandled WebSocket Error:{}\n".format( 179 | datetime.now().isoformat(), exception_type 180 | ) 181 | text += "LastSentText:\n{}\n".format(self._last_sent_text) 182 | text += "LastReceivedText:\n{}\n".format(self._last_received_text) 183 | text += "Exception trace: \n" 184 | text += "".join( 185 | traceback.format_exception(exception_type, exception_value, tb) 186 | ) 187 | return text 188 | 189 | 190 | def _record_last_sent_text(self, text: str): 191 | """ 192 | Record last sent text for debug purpose. 193 | """ 194 | self._last_sent_text = text[:1000] 195 | 196 | 197 | def _record_last_received_text(self, text: str): 198 | """ 199 | Record last received text for debug purpose. 200 | """ 201 | self._last_received_text = text[:1000] 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 | 230 | 231 | 232 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 本项目不再维护,请转到 https://github.com/mn3711698/mrm 2 | 3 | # singlecoin(支持windows+linux,交易所目前只支持币安,目前只支持单币运行) 4 | ## 注:执行RunBTC.py有多币,此为单币,多币不提供白嫖 5 | ## 非开源,慎用! 一定要加群,因为如果持仓情况与Tv的不同,那就肯定是亏损的 6 | 7 | # 执行Start.py(熊市牛B)目前只支持BNB,ETH 8 | 9 | # 执行RunBTC.py(牛市牛B)只支持BTCUSDT,YFIUSDT(别看下边的图有ZECUSDT直接用,参数不一样的).这个没有止损,要扛单注意仓位风险,也可以自己加止损 10 | ## 注:特别提醒,执行RunBTC.py的代码我是直接搬过来,因为我跑的是多币,这里是单币代码我没有实际跑。虽然这个效果好,但只是单币,所以我搞了多币,每个币单少,但二十多个币算下来单不少了。 11 | 12 | # 策略计算及下单平仓条件说明(为执行Start.py,执行RunBTC.py不提供说明) 13 | 14 | 两条移动线,对比两个线的值。在配置里line_poor,line_poor_stop,两个参数。当两个移动线的值相差大于line_poor,表示趋势明显向下或向上,要下单,当两个值小于line_poor_stop,表示很小的震荡或者趋势不明显,平仓。 15 | 16 | 已经在跑机器人,钉钉消息有几个值old_wave,Raw,Wave,Raw - wave。当Wave大于old_wave是趋势向上,反之趋势向下,Raw和Wave是两个移动线的值,Raw比Wave大是向上,反之向下,Raw - wave的绝对值大于line_poor就开仓,小于line_poor_stop就平仓。趋势相反了也平仓。 17 | 18 | 开仓:Wave大于old_wave且Raw - wave的绝对值大于line_poor开多,Wave不大于old_wave且Raw - wave的绝对值大于line_poor开空. 19 | 20 | 平仓:多单,Wave不大于old_wave或Raw - wave小于line_poor_stop平仓;空单,Wave大于old_wave或Raw - wave小于line_poor_stop平空. 21 | 22 | 因为用tradingview回测,没看到平仓条件且还达到下单条件马上下单的效果,所以平仓后要跟完一根K线再判断是不是要下单。不会平仓的同时马上反方向下单。 23 | 24 | # tradingview回测最优配置(bnb0.02,eth0.003),这里每几天进行一次对比记录,方便参考 25 | 26 | ## ETH: 27 | 2021-7-6 28 | line_poor=0.38,line_poor_stop=0.2(净利润24.79%,胜率40.74%); 29 | line_poor=0.626,line_poor_stop=0.5(净利润29.39%,胜率40.78%); 30 | 31 | 2021-7-5 32 | line_poor=0.38,line_poor_stop=0.2(净利润25.17%,胜率40.9%); 33 | line_poor=0.626,line_poor_stop=0.5(净利润29.69%,胜率41.05%); 34 | 35 | ## BNB: 36 | 37 | 2021-7-6 38 | line_poor=0.38,line_poor_stop=0.2(净利润23.92%,胜率42.35%); 39 | line_poor=0.04,line_poor_stop=0.05(净利润38.7%,胜率42.14%); 40 | line_poor=0.04,line_poor_stop=0.048(净利润38.85%,胜率41.93%); 41 | line_poor=0.053,line_poor_stop=0.048(净利润39.24%,胜率41.97%); 42 | 43 | 2021-7-5 44 | line_poor=0.38,line_poor_stop=0.2(净利润25.23%,胜率42.59%); 45 | line_poor=0.04,line_poor_stop=0.05(净利润39.19%,胜率42.42%); 46 | line_poor=0.04,line_poor_stop=0.048(净利润39.83%,胜率42.25%); 47 | line_poor=0.053,line_poor_stop=0.048(净利润40.22%,胜率42.29%); 48 | 49 | ## 有开发能力,如有在不泄漏策略代码并能对策略进行使用或者回测方案的可以联系我。(注:同一币种,同一配置参数,同一时间周期开仓及平仓的时机所有人一样) 50 | 51 | ## 以下为策略在tradingview采用15min线进行的回测(执行Start.py) 52 | BNB仓位0.02每单 53 | ![](https://github.com/mn3711698/singlecoin/blob/main/BNB0.02.png) 54 | BNB仓位1每单 55 | ![](https://github.com/mn3711698/singlecoin/blob/main/BNB1.png) 56 | ETH仓位0.003每单 57 | ![](https://github.com/mn3711698/singlecoin/blob/main/ETH0.003.png) 58 | ETH仓位1每单 59 | ![](https://github.com/mn3711698/singlecoin/blob/main/ETH1.png) 60 | BNB参数跑ETH仓位1每单 61 | ![](https://github.com/mn3711698/singlecoin/blob/main/BNB1TOETH1.png) 62 | 63 | BNB仓位0.02每单最新 64 | ![](https://github.com/mn3711698/singlecoin/blob/main/BNBnew.png) 65 | 66 | ETH仓位0.003每单最新 67 | ![](https://github.com/mn3711698/singlecoin/blob/main/eth20210726.png) 68 | 69 | ## 以下为策略在tradingview进行的回测(执行RunBTC.py) 70 | btcusdt 71 | ![](https://github.com/mn3711698/singlecoin/blob/main/btcusdt.png) 72 | 73 | yfiusdt 74 | ![](https://github.com/mn3711698/singlecoin/blob/main/yfiusdt.png) 75 | 76 | zecusdt 77 | ![](https://github.com/mn3711698/singlecoin/blob/main/zecusdt.png) 78 | 79 | ## 本项目只是提供代码,不对使用者因使用本代码实际产生的盈亏负责。不要跟我说开源,我从来就没有想过要开源,只是开放使用。 80 | 81 | ## 可以自行设置计算止盈的配置参数及修改止损配置 82 | 83 | # 注意(白嫖更要注意安全,因为核心代码没有开源,大家慎用) 84 | 85 | ## API的权限只需要有交易权限就够了,不要开提币权限,还要限制ip! 86 | 87 | ## API的权限只需要有交易权限就够了,不要开提币权限,还要限制ip! 88 | 89 | ## API的权限只需要有交易权限就够了,不要开提币权限,还要限制ip! 90 | 91 | # 需要准备云主机,windows支持64位的python,3.8或3.7,linux系统支持python3.6 92 | 93 | # 需要网络可以访问币安交易所,否则机器人无法使用 94 | 95 | ## windows使用说明(路径写死了) 96 | 下载本项目代码压缩包,放在C盘根目录下,解压,最终代码在C:\singlecoin\下。如果是git下载,也请代码放在C:\singlecoin\下,建议使用git下载,方便后续更新 97 | 98 | 先下载https://download.microsoft.com/download/5/f/7/5f7acaeb-8363-451f-9425-68a90f98b238/visualcppbuildtools_full.exe 99 | 安装时,直接下一步,不需要选择其他的。 100 | 101 | 安装相关库(只支持python3) pip3 install -r requirements.txt 或 pip install -r requirements.txt 102 | 103 | 填好config.py里边的配置项,确认python是不是64版本,如果使用的是python3.7要将RunUse里的TradeRun_w37.pyd重命名为TradeRun.pyd, 104 | strategies下的base_w37.pyd重命名为base.pyd, 105 | 如果使用的是python3.8要将RunUse里的TradeRun_w38.pyd重命名为TradeRun.pyd,strategies下的base_w38.pyd重命名为base.pyd 106 | 107 | 执行RunBTC.py将baseBTC_w37.pyd或base_w38.pyd重命名为baseBTC.pyd 108 | 109 | 到此,准备工作做好。在项目目录C:\singlecoin\下执行python3 Start.py,就可以躺着赚钱了 110 | 111 | 相关持仓及订单信息请看币安的网页或者APP对应的交易对下的数据。 112 | 113 | 如果后续有更新代码,可以直接git下载就好了。下载好后,关掉cdm窗口,重新打开窗口执行python3 Start.py就好了 114 | 115 | 注意:持仓方向是单向(双向持仓要改为单向否则无法下单),杠杆是交易所默认未进行另外设定 116 | ## linux使用说明(路径写死了) 117 | 下载本项目代码压缩包,放在/var/games/目录下,解压,最终代码在/var/games/singlecoin/下。 118 | 119 | 如果是git下载,也请代码放在/var/games/singlecoin/下,建议使用git下载,方便后续更新 120 | 121 | 安装相关库(只支持python3) pip3 install -r requirements.txt 或 pip install -r requirements.txt 122 | 123 | 填好config.py里边的配置项,确认python版本为python3.6, 124 | 要将RunUse里的TradeRun_l36.so重命名为TradeRun.so,strategies下的base_l36.so重命名为base.so 125 | 126 | 到此所有准备工作都做好了。在项目目录/var/games/singlecoin/下执行python3 Start.py 或python Start.py ,就可以躺着赚钱了 127 | 128 | 执行RunBTC.py将baseBTC_l36.so重命名为baseBTC.so 129 | 130 | 相关持仓及订单信息请看币安的网页或者APP对应的交易对下的数据。 131 | 132 | 建议使用Supervisor启动 133 | 134 | 如果后续有更新代码,可以直接git下载就好了。重新执行python3 Start.py就好了 135 | 136 | 注意:持仓方向是单向(双向持仓要改为单向否则无法下单),杠杆是交易所默认未进行另外设定 137 | 138 | ## 关于代码更新说明 139 | 建议使用git命令来下载,这样更新就不影响。 140 | 141 | # 更新日志 142 | 143 | 2021-09-03 增加TV回测图片 144 | 145 | 2021-09-03 增加一个策略。因为之前的策略空单交易好,多单不行,暂时没有想到办法优化,只能另搞一个策略。 146 | 147 | 2021-07-08 将下单改为市价,避免与TV不同步导致不明亏损 148 | 149 | 2021-07-08 优化多空不同处理参数(注释价格回撤止盈,可自行开启) 150 | 151 | 2021-07-05 优化取消订单再次下单,应对浮盈回吐变浮亏,增加两级价格回撤止盈(可自行设定) 152 | 153 | 2021-07-04 处理取消订单再次下单的bug 154 | 155 | 2021-07-03 对下单未成交取消进行再次下单处理 156 | 157 | 2021-07-02 简化策略,增加收益及减少亏损(重大更新) 158 | 159 | 2021-06-28 修改策略和止盈止损处理(大更新),策略是趋势策略,遇到震荡行情可以停用。 160 | 161 | 2021-06-01 增加strategy_flag参数,此参数控制策略版本,20210601对原策略进行修改,增加一个版本,对空单进行优化开仓,下单量会更小. 162 | 163 | 2021-05-20 修改配置文件参数排序,修改止盈止损位置的bug,增加新的配置参数tick_flag,提供多种止盈止损处理. 164 | 165 | 2021-05-19 增加配置项适应新的止盈止损处理,修改止盈止损处理,增加版本记录,增加新的下单价格处理 166 | 167 | 2021-05-17 增加止盈止损部分说明,增加亏损后加倍开单量的开关及处理代码 168 | 169 | 2021-05-15 增加对策略运行消息是否发钉钉的控制,增加从交易所币最小值的查询适应所有币交易,增加提供配置参数 170 | 171 | 2021-05-14 初始始上传 172 | 173 | 174 | # 联系(一定要加群,因为如果持仓情况与Tv的不同,那就肯定是亏损的) 175 | 打开http://small.yjyzj.cn 可以扫码加开发者微信或微信群 176 | 177 | # 关于核心代码编译的说明 178 | 179 | 大家想赚钱,那只有跟着大户的车赚点小钱。那些已经实现财富自由的人,请不要使用本机器人,为散户留口汤喝。 180 | 当一个交易对某开仓的方向资金量达到一定的程度,那必然会成为大户的目标,这样再好的策略或者机器人都只能是下酒菜。 181 | 所以,我为了一个策略能使用的足够久而不需要经常去修改参数只能对部分代码进行编译。 182 | 这样首先就让一部分担心安全的人没有了使用的冲动,那会使用的人必然资金量不大(因为我本人也是用30U去跑这个机器人)或者会使用小号去跑这个机器人。 183 | 这样的结果必然是只要机器人够好,那使用者都可以跟着大户的车赚点小钱。 184 | 当然我也有点小心思,想着这个机器人足够好的话,那我完全可以基于这个策略去做量化平台或者进行收费。为了收费核心代码编译是必须的。 185 | 186 | # 用到的链接 187 | 188 | wss://fstream.binance.com/ 币安ws 189 | https://fapi.binance.com 币安api 190 | https://oapi.dingtalk.com 发送钉钉webhook消息 191 | https://link.yjyzj.cn/ 我的,用来收集异常错误及发微信公众号消息,后续如果收费也会用这个进行授权 192 | 193 | ## 看到这还在担心资金安全问题,请不要使用本机器人 194 | 195 | -------------------------------------------------------------------------------- /getaway/binance_http.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | ############################################################################## 4 | # Author:QQ173782910 5 | ############################################################################## 6 | 7 | import requests 8 | import time 9 | import hmac 10 | import hashlib 11 | from enum import Enum 12 | from threading import Thread, Lock 13 | 14 | 15 | class OrderStatus(object): 16 | NEW = "NEW" 17 | PARTIALLY_FILLED = "PARTIALLY_FILLED" 18 | FILLED = "FILLED" 19 | CANCELED = "CANCELED" 20 | PENDING_CANCEL = "PENDING_CANCEL" 21 | REJECTED = "REJECTED" 22 | EXPIRED = "EXPIRED" 23 | 24 | class OrderType(Enum): 25 | LIMIT = "LIMIT" 26 | MARKET = "MARKET" 27 | STOP = "STOP" 28 | 29 | 30 | class RequestMethod(Enum): 31 | """ 32 | 请求的方法. 33 | """ 34 | GET = 'GET' 35 | POST = 'POST' 36 | PUT = 'PUT' 37 | DELETE = 'DELETE' 38 | 39 | class Interval(Enum): 40 | """ 41 | 请求的K线数据.. 42 | """ 43 | MINUTE_1 = '1m' 44 | MINUTE_3 = '3m' 45 | MINUTE_5 = '5m' 46 | MINUTE_15 = '15m' 47 | MINUTE_30 = '30m' 48 | HOUR_1 = '1h' 49 | HOUR_2 = '2h' 50 | HOUR_4 = '4h' 51 | HOUR_6 = '6h' 52 | HOUR_8 = '8h' 53 | HOUR_12 = '12h' 54 | DAY_1 = '1d' 55 | DAY_3 = '3d' 56 | WEEK_1 = '1w' 57 | MONTH_1 = '1M' 58 | 59 | class OrderSide(Enum): 60 | BUY = "BUY" 61 | SELL = "SELL" 62 | 63 | 64 | class BinanceFutureHttp(object): 65 | 66 | def __init__(self, key=None, secret=None, host=None, timeout=5): 67 | self.key = key 68 | self.secret = secret 69 | self.host = host if host else "https://fapi.binance.com" 70 | self.recv_window = 5000 71 | self.timeout = timeout 72 | self.order_count_lock = Lock() 73 | self.order_count = 1_000_000 74 | 75 | def build_parameters(self, params: dict): 76 | keys = list(params.keys()) 77 | keys.sort() 78 | return '&'.join([f"{key}={params[key]}" for key in params.keys()]) 79 | 80 | def request(self, req_method: RequestMethod, path: str, requery_dict=None, verify=False): 81 | url = self.host + path 82 | 83 | if verify: 84 | query_str = self._sign(requery_dict) 85 | url += '?' + query_str 86 | elif requery_dict: 87 | url += '?' + self.build_parameters(requery_dict) 88 | headers = {"X-MBX-APIKEY": self.key} 89 | return requests.request(req_method.value, url=url, headers=headers, timeout=self.timeout).json() 90 | 91 | def bbkline_request(self, req_method: RequestMethod, path: str, requery_dict=None, verify=False): 92 | url = "https://api.binance.com" + path 93 | 94 | if verify: 95 | query_str = self._sign(requery_dict) 96 | url += '?' + query_str 97 | elif requery_dict: 98 | url += '?' + self.build_parameters(requery_dict) 99 | headers = {"X-MBX-APIKEY": self.key} 100 | return requests.request(req_method.value, url=url, headers=headers, timeout=self.timeout).json() 101 | 102 | def server_time(self): 103 | path = '/fapi/v1/time' 104 | return self.request(req_method=RequestMethod.GET, path=path) 105 | 106 | def exchangeInfo(self): 107 | 108 | """ 109 | {'timezone': 'UTC', 'serverTime': 1570802268092, 'rateLimits': 110 | [{'rateLimitType': 'REQUEST_WEIGHT', 'interval': 'MINUTE', 'intervalNum': 1, 'limit': 1200}, 111 | {'rateLimitType': 'ORDERS', 'interval': 'MINUTE', 'intervalNum': 1, 'limit': 1200}], 112 | 'exchangeFilters': [], 'symbols': 113 | [{'symbol': 'BTCUSDT', 'status': 'TRADING', 'maintMarginPercent': '2.5000', 'requiredMarginPercent': '5.0000', 114 | 'baseAsset': 'BTC', 'quoteAsset': 'USDT', 'pricePrecision': 2, 'quantityPrecision': 3, 'baseAssetPrecision': 8, 115 | 'quotePrecision': 8, 116 | 'filters': [{'minPrice': '0.01', 'maxPrice': '100000', 'filterType': 'PRICE_FILTER', 'tickSize': '0.01'}, 117 | {'stepSize': '0.001', 'filterType': 'LOT_SIZE', 'maxQty': '1000', 'minQty': '0.001'}, 118 | {'stepSize': '0.001', 'filterType': 'MARKET_LOT_SIZE', 'maxQty': '1000', 'minQty': '0.001'}, 119 | {'limit': 200, 'filterType': 'MAX_NUM_ORDERS'}, 120 | {'multiplierDown': '0.8500', 'multiplierUp': '1.1500', 'multiplierDecimal': '4', 'filterType': 'PERCENT_PRICE'}], 121 | 'orderTypes': ['LIMIT', 'MARKET', 'STOP'], 'timeInForce': ['GTC', 'IOC', 'FOK', 'GTX']}]} 122 | 123 | :return: 124 | """ 125 | 126 | path = '/fapi/v1/exchangeInfo' 127 | return self.request(req_method=RequestMethod.GET, path=path) 128 | 129 | def order_book(self, symbol, limit=5): 130 | limits = [5, 10, 20, 50, 100, 500, 1000] 131 | if limit not in limits: 132 | limit = 5 133 | 134 | path = "/fapi/v1/depth" 135 | query_dict = {"symbol": symbol, 136 | "limit": limit 137 | } 138 | return self.request(RequestMethod.GET, path, query_dict) 139 | 140 | def get_kline(self, symbol, interval: Interval, start_time=None, end_time=None, limit=500, max_try_time=10): 141 | """ 142 | 143 | :param symbol: 144 | :param interval: 145 | :param start_time: 146 | :param end_time: 147 | :param limit: 148 | :return: 149 | [ 150 | 1499040000000, // 开盘时间 151 | "0.01634790", // 开盘价 152 | "0.80000000", // 最高价 153 | "0.01575800", // 最低价 154 | "0.01577100", // 收盘价(当前K线未结束的即为最新价) 155 | "148976.11427815", // 成交量 156 | 1499644799999, // 收盘时间 157 | "2434.19055334", // 成交额 158 | 308, // 成交笔数 159 | "1756.87402397", // 主动买入成交量 160 | "28.46694368", // 主动买入成交额 161 | "17928899.62484339" // 请忽略该参数 162 | ] 163 | """ 164 | path = "/fapi/v1/klines" 165 | 166 | query_dict = { 167 | "symbol": symbol, 168 | "interval": interval.value, 169 | "limit": limit 170 | } 171 | 172 | if start_time: 173 | query_dict['startTime'] = start_time 174 | 175 | if end_time: 176 | query_dict['endTime'] = end_time 177 | 178 | for i in range(max_try_time): 179 | data = self.request(RequestMethod.GET, path, query_dict) 180 | if isinstance(data, list) and len(data): 181 | return data 182 | 183 | def get_bbkline(self, symbol, interval: Interval, start_time=None, end_time=None, limit=500, max_try_time=10): 184 | """ 185 | 186 | :param symbol: 187 | :param interval: 188 | :param start_time: 189 | :param end_time: 190 | :param limit: 191 | :return: 192 | [ 193 | 1499040000000, // 开盘时间 194 | "0.01634790", // 开盘价 195 | "0.80000000", // 最高价 196 | "0.01575800", // 最低价 197 | "0.01577100", // 收盘价(当前K线未结束的即为最新价) 198 | "148976.11427815", // 成交量 199 | 1499644799999, // 收盘时间 200 | "2434.19055334", // 成交额 201 | 308, // 成交笔数 202 | "1756.87402397", // 主动买入成交量 203 | "28.46694368", // 主动买入成交额 204 | "17928899.62484339" // 请忽略该参数 205 | ] 206 | """ 207 | # path = "/fapi/v1/klines" 208 | path = "/api/v3/klines" 209 | 210 | 211 | query_dict = { 212 | "symbol": symbol, 213 | "interval": interval.value, 214 | "limit": limit 215 | } 216 | 217 | if start_time: 218 | query_dict['startTime'] = start_time 219 | 220 | if end_time: 221 | query_dict['endTime'] = end_time 222 | 223 | for i in range(max_try_time): 224 | data = self.bbkline_request(RequestMethod.GET, path, query_dict) 225 | if isinstance(data, list) and len(data): 226 | return data 227 | 228 | def get_latest_price(self, symbol): 229 | path = "/fapi/v1/ticker/price" 230 | query_dict = {"symbol": symbol} 231 | return self.request(RequestMethod.GET, path, query_dict) 232 | 233 | def get_ticker(self, symbol): 234 | path = "/fapi/v1/ticker/bookTicker" 235 | query_dict = {"symbol": symbol} 236 | return self.request(RequestMethod.GET, path, query_dict) 237 | 238 | def _new_order_id(self): 239 | """ 240 | 生成一个order_id.. 241 | :return: 242 | """ 243 | with self.order_count_lock: 244 | self.order_count += 1 245 | return self.order_count 246 | 247 | def _timestamp(self): 248 | return int(time.time() * 1000) 249 | 250 | def _sign(self, params): 251 | 252 | requery_string = self.build_parameters(params) 253 | hexdigest = hmac.new(self.secret.encode('utf8'), requery_string.encode("utf-8"), hashlib.sha256).hexdigest() 254 | return requery_string + '&signature=' + str(hexdigest) 255 | 256 | def order_id(self): 257 | return str(self._timestamp() + self._new_order_id()) 258 | 259 | def place_order(self, symbol: str, side: OrderSide, order_type:OrderType, quantity, price, client_prefix=None, time_inforce="GTC", recvWindow=5000, stop_price=0): 260 | 261 | """ 262 | 下单.. 263 | :param symbol: BTCUSDT 264 | :param side: BUY or SELL 265 | :param type: LIMIT MARKET STOP 266 | :param quantity: 数量. 267 | :param price: 价格 268 | :param stop_price: 停止单的价格. 269 | :param time_inforce: 270 | :param params: 其他参数 271 | 272 | LIMIT : timeInForce, quantity, price 273 | MARKET : quantity 274 | STOP: quantity, price, stopPrice 275 | :return: 276 | 277 | """ 278 | 279 | path = '/fapi/v1/order' 280 | 281 | params = { 282 | "symbol": symbol, 283 | "side": side.value, 284 | "type": order_type.value, 285 | "quantity": quantity, 286 | "price": price, 287 | "recvWindow": recvWindow, 288 | "timestamp": self._timestamp() 289 | } 290 | 291 | if order_type == OrderType.LIMIT: 292 | params['timeInForce'] = time_inforce 293 | 294 | if order_type == OrderType.MARKET: 295 | if params.get('price'): 296 | del params['price'] 297 | 298 | if order_type == OrderType.STOP: 299 | if stop_price > 0: 300 | params["stopPrice"] = stop_price 301 | else: 302 | raise ValueError("stopPrice must greater than 0") 303 | return self.request(RequestMethod.POST, path=path, requery_dict=params, verify=True) 304 | 305 | def get_order(self,symbol, order_id=None): 306 | path = "/fapi/v1/order" 307 | query_dict = {"symbol": symbol, "timestamp": self._timestamp()} 308 | if order_id: 309 | query_dict["orderId"] = order_id 310 | 311 | return self.request(RequestMethod.GET, path, query_dict, verify=True) 312 | 313 | def cancel_order(self, symbol, order_id=None): 314 | path = "/fapi/v1/order" 315 | params = {"symbol": symbol, "timestamp": self._timestamp()} 316 | if order_id: 317 | params["orderId"] = order_id 318 | 319 | return self.request(RequestMethod.DELETE, path, params, verify=True) 320 | 321 | def get_open_orders(self, symbol=None): 322 | path = "/fapi/v1/openOrders" 323 | 324 | params = {"timestamp": self._timestamp()} 325 | if symbol: 326 | params["symbol"] = symbol 327 | 328 | return self.request(RequestMethod.GET, path, params, verify=True) 329 | 330 | def get_balance(self): 331 | """ 332 | [{'accountId': 18396, 'asset': 'USDT', 'balance': '530.21334791', 'withdrawAvailable': '530.21334791', 'updateTime': 1570330854015}] 333 | :return: 334 | """ 335 | path = "/fapi/v1/balance" 336 | params = {"timestamp": self._timestamp()} 337 | 338 | return self.request(RequestMethod.GET, path=path, requery_dict=params, verify=True) 339 | 340 | def get_account_info(self): 341 | """ 342 | {'feeTier': 2, 'canTrade': True, 'canDeposit': True, 'canWithdraw': True, 'updateTime': 0, 'totalInitialMargin': '0.00000000', 343 | 'totalMaintMargin': '0.00000000', 'totalWalletBalance': '530.21334791', 'totalUnrealizedProfit': '0.00000000', 344 | 'totalMarginBalance': '530.21334791', 'totalPositionInitialMargin': '0.00000000', 'totalOpenOrderInitialMargin': '0.00000000', 345 | 'maxWithdrawAmount': '530.2133479100000', 'assets': 346 | [{'asset': 'USDT', 'walletBalance': '530.21334791', 'unrealizedProfit': '0.00000000', 'marginBalance': '530.21334791', 347 | 'maintMargin': '0.00000000', 'initialMargin': '0.00000000', 'positionInitialMargin': '0.00000000', 'openOrderInitialMargin': '0.00000000', 348 | 'maxWithdrawAmount': '530.2133479100000'}]} 349 | :return: 350 | """ 351 | path = "/fapi/v1/account" 352 | params = {"timestamp": self._timestamp()} 353 | return self.request(RequestMethod.GET, path, params, verify=True) 354 | 355 | def get_position_info(self): 356 | """ 357 | [{'symbol': 'BTCUSDT', 'positionAmt': '0.000', 'entryPrice': '0.00000', 'markPrice': '8326.40833498', 'unRealizedProfit': '0.00000000', 'liquidationPrice': '0'}] 358 | :return: 359 | """ 360 | path = "/fapi/v1/positionRisk" 361 | params = {"timestamp": self._timestamp()} 362 | return self.request(RequestMethod.GET, path, params, verify=True) 363 | 364 | def get_openInterestHist(self,symbol,period='5m',limit=10): #合约持仓量 365 | path = "/futures/data/openInterestHist" 366 | query_dict = {"symbol": symbol,"period":period,"limit":limit} 367 | return self.request(RequestMethod.GET, path, query_dict) 368 | 369 | def get_topLongShortAccountRatio(self,symbol,period='5m',limit=10):#大户账户数多空比 370 | path = "/futures/data/topLongShortAccountRatio" 371 | query_dict = {"symbol": symbol,"period":period,"limit":limit} 372 | return self.request(RequestMethod.GET, path, query_dict) 373 | 374 | def get_topLongShortPositionRatio(self,symbol,period='5m',limit=10):#大户持仓量多空比 375 | path = "/futures/data/topLongShortPositionRatio" 376 | query_dict = {"symbol": symbol,"period":period,"limit":limit} 377 | return self.request(RequestMethod.GET, path, query_dict) 378 | 379 | def get_globalLongShortAccountRatio(self,symbol,period='5m',limit=10):#多空持仓人数比 380 | path = "/futures/data/globalLongShortAccountRatio" 381 | query_dict = {"symbol": symbol,"period":period,"limit":limit} 382 | return self.request(RequestMethod.GET, path, query_dict) 383 | 384 | def get_takerlongshortRatio(self,symbol,period='5m',limit=10):#合约主动买卖量 385 | path = "/futures/data/takerlongshortRatio" 386 | query_dict = {"symbol": symbol,"period":period,"limit":limit} 387 | return self.request(RequestMethod.GET, path, query_dict) 388 | 389 | 390 | -------------------------------------------------------------------------------- /strategies/LineWith.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | ############################################################################## 3 | # Author:QQ173782910 4 | ############################################################################## 5 | 6 | from datetime import datetime 7 | from strategies import Base 8 | from getaway.send_msg import dingding, wx_send_msg 9 | 10 | 11 | class LineWith(Base): 12 | 13 | def on_pos_data(self, pos_dict): 14 | # 先判断是否有仓位,如果是多头的仓位, 然后检查下是多头还是空头,设置相应的止损的价格.. 15 | current_pos = float(pos_dict['positionAmt']) 16 | self.unRealizedProfit = float(pos_dict['unRealizedProfit']) 17 | entryPrice = float(pos_dict['entryPrice']) 18 | if self.enter_price == 0 or self.enter_price != entryPrice: 19 | self.enter_price = entryPrice 20 | if current_pos > 0: 21 | self.stoploss_price = entryPrice * (1 - self.long_stoploss) 22 | self.takeprofit_price = entryPrice * (1 + self.long_takeprofit) 23 | elif current_pos < 0: 24 | self.stoploss_price = entryPrice * (1 + self.short_stoploss) 25 | self.takeprofit_price = entryPrice * (1 - self.short_takeprofit) 26 | if self.pos != 0: 27 | if self.unRealizedProfit > 0: 28 | self.maxunRealizedProfit = max(self.maxunRealizedProfit, self.unRealizedProfit) 29 | elif self.unRealizedProfit < 0: 30 | self.lowProfit = min(self.lowProfit, self.unRealizedProfit) 31 | 32 | if self.pos != current_pos: # 检查仓位是否是一一样的. 33 | 34 | if current_pos == 0: 35 | dingding(f"仓位检查:{self.symbol},交易所帐户仓位为0,无持仓,系统仓位为:{self.pos},重置为0", symbols=self.symbol) 36 | self.pos = 0 37 | self.sync_data() 38 | return 39 | elif current_pos != 0: 40 | if self.HYJ_jd_ss != 0: 41 | self.HYJ_jd_ss = 0 42 | dingding(f"仓位检查:{self.symbol},交易所帐户仓位为:{current_pos},有持仓,系统仓位为:{self.pos},重置为:{current_pos}", symbols=self.symbol) 43 | self.pos = current_pos 44 | self.sync_data() 45 | return 46 | if current_pos == 0 and len(self.open_orders) == 0: 47 | coraup = self.cora_wave > self.old_cora_wave 48 | Cora_Raw_wave = self.cora_raw - self.cora_wave 49 | if coraup: # 多单方向 50 | raw_wave = abs(Cora_Raw_wave) > self.long_line_poor 51 | else: # 空单方向 52 | raw_wave = abs(Cora_Raw_wave) > self.short_line_poor 53 | if self.pos_flag == 1 and coraup and raw_wave: # 开多未成交,取消未成交订单再下单 54 | self.pos_flag = 0 55 | self.pos = self.round_to(self.trading_size, self.min_volume) 56 | enter_price = self.ask 57 | res_buy = self.buy(enter_price, abs(self.pos), mark=True) 58 | self.enter_price = enter_price 59 | self.stoploss_price = enter_price * (1 - self.long_stoploss) 60 | self.takeprofit_price = enter_price * (1 + self.long_takeprofit) 61 | self.high_price = enter_price 62 | self.low_price = enter_price 63 | self.maxunRealizedProfit = 0 64 | self.unRealizedProfit = 0 65 | self.lowProfit = 0 66 | self.pos_update_time = datetime.now() 67 | self.sync_data() 68 | HYJ_jd_first = f"交易对:{self.symbol},仓位:{self.pos}" 69 | HYJ_jd_tradeType = "开多2" 70 | HYJ_jd_curAmount = f"{enter_price}" 71 | HYJ_jd_remark = f"最新价:{self.last_price}" 72 | dingding(f"开多2,交易所返回:{res_buy}", symbols=self.symbol) 73 | wx_send_msg(HYJ_jd_first, HYJ_jd_tradeType, HYJ_jd_curAmount, HYJ_jd_remark) 74 | elif self.pos_flag == -1 and not coraup and raw_wave: # 开空未成交,取消未成交订单再下单 75 | self.pos_flag = 0 76 | self.pos = self.round_to(self.trading_size, self.min_volume) 77 | enter_price = self.bid 78 | res_sell = self.sell(enter_price, abs(self.pos), mark=True) 79 | self.pos = -self.pos 80 | self.enter_price = enter_price 81 | self.stoploss_price = enter_price * (1 + self.short_stoploss) 82 | self.takeprofit_price = enter_price * (1 - self.short_takeprofit) 83 | self.high_price = enter_price 84 | self.low_price = enter_price 85 | self.maxunRealizedProfit = 0 86 | self.unRealizedProfit = 0 87 | self.lowProfit = 0 88 | self.pos_update_time = datetime.now() 89 | self.sync_data() 90 | HYJ_jd_first = f"交易对:{self.symbol},仓位:{self.pos}" 91 | HYJ_jd_tradeType = "开空2" 92 | HYJ_jd_curAmount = f"{enter_price}" 93 | HYJ_jd_remark = f"最新价:{self.last_price}" 94 | dingding(f"开空2,交易所返回:{res_sell}", symbols=self.symbol) 95 | wx_send_msg(HYJ_jd_first, HYJ_jd_tradeType, HYJ_jd_curAmount, HYJ_jd_remark) 96 | else: 97 | self.pos_flag = 0 98 | 99 | def on_ticker_data(self, ticker): 100 | self.ticker_data(ticker) 101 | 102 | def ticker_data(self, ticker): 103 | 104 | if self.symbol == ticker['symbol']: 105 | last_price = float(ticker['last_price']) # 最新的价格. 106 | self.last_price = last_price 107 | 108 | if self.pos != 0: 109 | if self.high_price > 0: 110 | self.high_price = max(self.high_price, self.last_price) 111 | if self.low_price > 0: 112 | self.low_price = min(self.low_price, self.last_price) 113 | 114 | if self.pos == 0: # 无持仓 115 | 116 | if self.HYJ_jd_ss == 1: # 策略计算出来是开多信号 117 | self.HYJ_jd_ss = 0 118 | self.pos = self.round_to(self.trading_size, self.min_volume) 119 | enter_price = self.ask 120 | res_buy = self.buy(enter_price, abs(self.pos), mark=True) 121 | self.enter_price = enter_price 122 | self.stoploss_price = enter_price * (1 - self.long_stoploss) 123 | self.takeprofit_price = enter_price * (1 + self.long_takeprofit) 124 | self.high_price = enter_price 125 | self.low_price = enter_price 126 | self.maxunRealizedProfit = 0 127 | self.unRealizedProfit = 0 128 | self.lowProfit = 0 129 | self.pos_update_time = datetime.now() 130 | self.sync_data() 131 | HYJ_jd_first = f"交易对:{self.symbol},仓位:{self.pos}" 132 | HYJ_jd_tradeType = "开多" 133 | HYJ_jd_curAmount = f"{enter_price}" 134 | HYJ_jd_remark = f"最新价:{self.last_price}" 135 | dingding(f"开多交易所返回:{res_buy}", symbols=self.symbol) 136 | wx_send_msg(HYJ_jd_first, HYJ_jd_tradeType, HYJ_jd_curAmount, HYJ_jd_remark) 137 | 138 | elif self.HYJ_jd_ss == -1: # 策略计算出来是开空信号 139 | self.HYJ_jd_ss = 0 140 | self.pos = self.round_to(self.trading_size, self.min_volume) 141 | enter_price = self.bid 142 | res_sell = self.sell(enter_price, abs(self.pos), mark=True) 143 | self.pos = -self.pos 144 | self.enter_price = enter_price 145 | self.stoploss_price = enter_price * (1 + self.short_stoploss) 146 | self.takeprofit_price = enter_price * (1 - self.short_takeprofit) 147 | self.high_price = enter_price 148 | self.low_price = enter_price 149 | self.maxunRealizedProfit = 0 150 | self.unRealizedProfit = 0 151 | self.lowProfit = 0 152 | self.pos_update_time = datetime.now() 153 | self.sync_data() 154 | HYJ_jd_first = f"交易对:{self.symbol},仓位:{self.pos}" 155 | HYJ_jd_tradeType = "开空" 156 | HYJ_jd_curAmount = f"{enter_price}" 157 | HYJ_jd_remark = f"最新价:{self.last_price}" 158 | dingding(f"开空交易所返回:{res_sell}", symbols=self.symbol) 159 | wx_send_msg(HYJ_jd_first, HYJ_jd_tradeType, HYJ_jd_curAmount, HYJ_jd_remark) 160 | 161 | elif self.HYJ_jd_ss == 2: # 趋势反转后平空后开多 162 | self.HYJ_jd_ss = 0 163 | self.pos = self.round_to(self.trading_size, self.min_volume) 164 | enter_price = self.ask 165 | res_buy = self.buy(enter_price, abs(self.pos), mark=True) 166 | self.enter_price = enter_price 167 | self.stoploss_price = enter_price * (1 - self.long_stoploss) 168 | self.takeprofit_price = enter_price * (1 + self.long_takeprofit) 169 | self.high_price = enter_price 170 | self.low_price = enter_price 171 | self.maxunRealizedProfit = 0 172 | self.unRealizedProfit = 0 173 | self.lowProfit = 0 174 | self.pos_update_time = datetime.now() 175 | self.sync_data() 176 | HYJ_jd_first = f"交易对:{self.symbol},仓位:{self.pos}" 177 | HYJ_jd_tradeType = "开多3" 178 | HYJ_jd_curAmount = f"{enter_price}" 179 | HYJ_jd_remark = f"最新价:{self.last_price}" 180 | dingding(f"开多交易所返回:{res_buy}", symbols=self.symbol) 181 | wx_send_msg(HYJ_jd_first, HYJ_jd_tradeType, HYJ_jd_curAmount, HYJ_jd_remark) 182 | 183 | elif self.HYJ_jd_ss == -2: # 趋势反转后平多后开空 184 | self.HYJ_jd_ss = 0 185 | self.pos = self.round_to(self.trading_size, self.min_volume) 186 | enter_price = self.bid 187 | res_sell = self.sell(enter_price, abs(self.pos), mark=True) 188 | self.pos = -self.pos 189 | self.enter_price = enter_price 190 | self.stoploss_price = enter_price * (1 + self.short_stoploss) 191 | self.takeprofit_price = enter_price * (1 - self.short_takeprofit) 192 | self.high_price = enter_price 193 | self.low_price = enter_price 194 | self.maxunRealizedProfit = 0 195 | self.unRealizedProfit = 0 196 | self.lowProfit = 0 197 | self.pos_update_time = datetime.now() 198 | self.sync_data() 199 | HYJ_jd_first = f"交易对:{self.symbol},仓位:{self.pos}" 200 | HYJ_jd_tradeType = "开空3" 201 | HYJ_jd_curAmount = f"{enter_price}" 202 | HYJ_jd_remark = f"最新价:{self.last_price}" 203 | dingding(f"开空交易所返回:{res_sell}", symbols=self.symbol) 204 | wx_send_msg(HYJ_jd_first, HYJ_jd_tradeType, HYJ_jd_curAmount, HYJ_jd_remark) 205 | 206 | elif self.pos > 0: # 多单持仓,目前止损是以 HYJ_jd_ss = 11,如有需要其他的止损请在下边增加自己的代码 207 | 208 | enter_price = self.bid2 # +1 209 | Profit = self.round_to((enter_price - self.enter_price) * abs(self.pos), self.min_price) 210 | 211 | if self.HYJ_jd_ss == 11: # self.HYJ_jd_ss = 11 是趋势反转了 212 | self.HYJ_jd_ss_old = 1 213 | res_sell = self.sell(enter_price, abs(self.pos), mark=True) 214 | self.HYJ_jd_ss = 0 215 | self.stop_price = 0 216 | HYJ_jd_first = "趋势反转平多:交易对:%s,最大亏损:%s,最大利润:%s,当前利润:%s,仓位:%s" % ( 217 | self.symbol, self.lowProfit, self.maxunRealizedProfit, self.unRealizedProfit, self.pos) 218 | self.pos = 0 219 | HYJ_jd_tradeType = "平多" 220 | HYJ_jd_curAmount = "%s" % enter_price 221 | HYJ_jd_remark = "趋势反转平多:%s,最新价:%s,最高价:%s,最低价:%s" % ( 222 | Profit, self.last_price, self.high_price, self.low_price) 223 | self.enter_price = 0 224 | self.high_price = 0 225 | self.low_price = 0 226 | self.stoploss_price = 0 227 | self.takeprofit_price = 0 228 | self.maxunRealizedProfit = 0 229 | self.unRealizedProfit = 0 230 | self.lowProfit = 0 231 | self.sync_data() 232 | dingding(f"趋势反转平多,交易所返回:{res_sell}", symbols=self.symbol) 233 | wx_send_msg(HYJ_jd_first, HYJ_jd_tradeType, HYJ_jd_curAmount, HYJ_jd_remark) 234 | 235 | elif self.HYJ_jd_ss == 22: # self.HYJ_jd_ss = 22 是趋势收缩了 236 | self.HYJ_jd_ss_old = 1 237 | res_sell = self.sell(enter_price, abs(self.pos), mark=True) 238 | self.HYJ_jd_ss = 0 239 | self.stop_price = 0 240 | HYJ_jd_first = "趋势收缩平多:交易对:%s,最大亏损:%s,最大利润:%s,当前利润:%s,仓位:%s" % ( 241 | self.symbol, self.lowProfit, self.maxunRealizedProfit, self.unRealizedProfit, self.pos) 242 | self.pos = 0 243 | HYJ_jd_tradeType = "平多" 244 | HYJ_jd_curAmount = "%s" % enter_price 245 | HYJ_jd_remark = "趋势收缩平多:%s,最新价:%s,最高价:%s,最低价:%s" % ( 246 | Profit, self.last_price, self.high_price, self.low_price) 247 | self.enter_price = 0 248 | self.high_price = 0 249 | self.low_price = 0 250 | self.stoploss_price = 0 251 | self.takeprofit_price = 0 252 | self.maxunRealizedProfit = 0 253 | self.unRealizedProfit = 0 254 | self.lowProfit = 0 255 | self.sync_data() 256 | dingding(f"趋势收缩平多,交易所返回:{res_sell}", symbols=self.symbol) 257 | wx_send_msg(HYJ_jd_first, HYJ_jd_tradeType, HYJ_jd_curAmount, HYJ_jd_remark) 258 | 259 | elif self.last_price < self.stoploss_price: 260 | self.HYJ_jd_ss_old = 1 261 | res_sell = self.sell(enter_price, abs(self.pos), mark=True) 262 | self.HYJ_jd_ss = 0 263 | 264 | self.times += 1 # 这个是连续亏损计数 265 | self.stop_price = 0 266 | HYJ_jd_first = "止损平多:交易对:%s,最大亏损:%s,最大利润:%s,当前利润:%s,仓位:%s" % ( 267 | self.symbol, self.lowProfit, self.maxunRealizedProfit, self.unRealizedProfit, self.pos) 268 | self.pos = 0 269 | HYJ_jd_tradeType = "止损平多" 270 | HYJ_jd_curAmount = "%s" % enter_price 271 | HYJ_jd_remark = "止损平多:%s,最新价:%s,最高价:%s,最低价:%s" % ( 272 | Profit, self.last_price, self.high_price, self.low_price) 273 | self.stoploss_price = 0 274 | self.takeprofit_price = 0 275 | self.enter_price = 0 276 | self.high_price = 0 277 | self.low_price = 0 278 | self.maxunRealizedProfit = 0 279 | self.unRealizedProfit = 0 280 | self.lowProfit = 0 281 | self.sync_data() 282 | dingding(f"止损平多,交易所返回:{res_sell}") 283 | wx_send_msg(HYJ_jd_first, HYJ_jd_tradeType, HYJ_jd_curAmount, HYJ_jd_remark) 284 | 285 | elif self.takeprofit_price != 0 and self.last_price > self.takeprofit_price: 286 | self.HYJ_jd_ss_old = 1 287 | res_sell = self.sell(enter_price, abs(self.pos), mark=True) 288 | self.HYJ_jd_ss = 0 289 | HYJ_jd_first = "止盈A:交易对:%s,最大亏损:%s,最大利润:%s,当前利润:%s,仓位:%s" % ( 290 | self.symbol, self.lowProfit, self.maxunRealizedProfit, self.unRealizedProfit, self.pos) 291 | self.pos = 0 292 | HYJ_jd_remark = "净利:%s,最新价:%s,最高价:%s,最低价:%s" % ( 293 | Profit, self.last_price, self.high_price, self.low_price) 294 | self.times = 0 295 | self.stoploss_price = 0 296 | self.takeprofit_price = 0 297 | self.stop_price = 0 298 | HYJ_jd_tradeType = "平多" 299 | HYJ_jd_curAmount = "%s" % enter_price 300 | self.enter_price = 0 301 | self.high_price = 0 302 | self.low_price = 0 303 | self.maxunRealizedProfit = 0 304 | self.unRealizedProfit = 0 305 | self.lowProfit = 0 306 | self.sync_data() 307 | dingding(f"多单,止盈A,交易所返回:{res_sell}") 308 | wx_send_msg(HYJ_jd_first, HYJ_jd_tradeType, HYJ_jd_curAmount, HYJ_jd_remark) 309 | 310 | # elif self.unRealizedProfit > 0.1 and self.high_price - self.last_price > 1: 311 | # 312 | # self.HYJ_jd_ss_old = 1 313 | # res_sell = self.sell(enter_price, abs(self.pos)) 314 | # self.HYJ_jd_ss = 0 315 | # HYJ_jd_first = "止盈B:交易对:%s,最大亏损:%s,最大利润:%s,当前利润:%s,仓位:%s" % ( 316 | # self.symbol, self.lowProfit, self.maxunRealizedProfit, self.unRealizedProfit, self.pos) 317 | # self.pos = 0 318 | # HYJ_jd_remark = "净利:%s,最新价:%s,最高价:%s,最低价:%s" % ( 319 | # Profit, self.last_price, self.high_price, self.low_price) 320 | # self.times = 0 321 | # self.stoploss_price = 0 322 | # self.takeprofit_price = 0 323 | # self.stop_price = 0 324 | # HYJ_jd_tradeType = "平多" 325 | # HYJ_jd_curAmount = "%s" % enter_price 326 | # self.enter_price = 0 327 | # self.high_price = 0 328 | # self.low_price = 0 329 | # self.maxunRealizedProfit = 0 330 | # self.unRealizedProfit = 0 331 | # self.lowProfit = 0 332 | # self.sync_data() 333 | # dingding(f"多单,止盈B,交易所返回:{res_sell}") 334 | # wx_send_msg(HYJ_jd_first, HYJ_jd_tradeType, HYJ_jd_curAmount, HYJ_jd_remark) 335 | # 336 | # elif self.unRealizedProfit > 0.05 and self.high_price - self.last_price > 1: 337 | # 338 | # self.HYJ_jd_ss_old = 1 339 | # res_sell = self.sell(enter_price, abs(self.pos)) 340 | # self.HYJ_jd_ss = 0 341 | # HYJ_jd_first = "止盈C:交易对:%s,最大亏损:%s,最大利润:%s,当前利润:%s,仓位:%s" % ( 342 | # self.symbol, self.lowProfit, self.maxunRealizedProfit, self.unRealizedProfit, self.pos) 343 | # self.pos = 0 344 | # HYJ_jd_remark = "净利:%s,最新价:%s,最高价:%s,最低价:%s" % ( 345 | # Profit, self.last_price, self.high_price, self.low_price) 346 | # self.times = 0 347 | # self.stoploss_price = 0 348 | # self.takeprofit_price = 0 349 | # self.stop_price = 0 350 | # HYJ_jd_tradeType = "平多" 351 | # HYJ_jd_curAmount = "%s" % enter_price 352 | # self.enter_price = 0 353 | # self.high_price = 0 354 | # self.low_price = 0 355 | # self.maxunRealizedProfit = 0 356 | # self.unRealizedProfit = 0 357 | # self.lowProfit = 0 358 | # self.sync_data() 359 | # dingding(f"多单,止盈C,交易所返回:{res_sell}") 360 | # wx_send_msg(HYJ_jd_first, HYJ_jd_tradeType, HYJ_jd_curAmount, HYJ_jd_remark) 361 | # 362 | # elif self.maxunRealizedProfit > 0.1 and self.high_price - self.last_price > 2: 363 | # 364 | # self.HYJ_jd_ss_old = 1 365 | # res_sell = self.sell(enter_price, abs(self.pos)) 366 | # self.HYJ_jd_ss = 0 367 | # HYJ_jd_first = "止盈D:交易对:%s,最大亏损:%s,最大利润:%s,当前利润:%s,仓位:%s" % ( 368 | # self.symbol, self.lowProfit, self.maxunRealizedProfit, self.unRealizedProfit, self.pos) 369 | # self.pos = 0 370 | # HYJ_jd_remark = "净利:%s,最新价:%s,最高价:%s,最低价:%s" % ( 371 | # Profit, self.last_price, self.high_price, self.low_price) 372 | # self.times = 0 373 | # self.stoploss_price = 0 374 | # self.takeprofit_price = 0 375 | # self.stop_price = 0 376 | # HYJ_jd_tradeType = "平多" 377 | # HYJ_jd_curAmount = "%s" % enter_price 378 | # self.enter_price = 0 379 | # self.high_price = 0 380 | # self.low_price = 0 381 | # self.maxunRealizedProfit = 0 382 | # self.unRealizedProfit = 0 383 | # self.lowProfit = 0 384 | # self.sync_data() 385 | # dingding(f"多单,止盈D,交易所返回:{res_sell}") 386 | # wx_send_msg(HYJ_jd_first, HYJ_jd_tradeType, HYJ_jd_curAmount, HYJ_jd_remark) 387 | # 388 | # elif self.maxunRealizedProfit > 0.05 and self.high_price - self.last_price > 2: 389 | # 390 | # self.HYJ_jd_ss_old = 1 391 | # res_sell = self.sell(enter_price, abs(self.pos)) 392 | # self.HYJ_jd_ss = 0 393 | # HYJ_jd_first = "止盈E:交易对:%s,最大亏损:%s,最大利润:%s,当前利润:%s,仓位:%s" % ( 394 | # self.symbol, self.lowProfit, self.maxunRealizedProfit, self.unRealizedProfit, self.pos) 395 | # self.pos = 0 396 | # HYJ_jd_remark = "净利:%s,最新价:%s,最高价:%s,最低价:%s" % ( 397 | # Profit, self.last_price, self.high_price, self.low_price) 398 | # self.times = 0 399 | # self.stoploss_price = 0 400 | # self.takeprofit_price = 0 401 | # self.stop_price = 0 402 | # HYJ_jd_tradeType = "平多" 403 | # HYJ_jd_curAmount = "%s" % enter_price 404 | # self.enter_price = 0 405 | # self.high_price = 0 406 | # self.low_price = 0 407 | # self.maxunRealizedProfit = 0 408 | # self.unRealizedProfit = 0 409 | # self.lowProfit = 0 410 | # self.sync_data() 411 | # dingding(f"多单,止盈E,交易所返回:{res_sell}") 412 | # wx_send_msg(HYJ_jd_first, HYJ_jd_tradeType, HYJ_jd_curAmount, HYJ_jd_remark) 413 | 414 | elif self.pos < 0: # 空单持仓 415 | enter_price = self.ask2 416 | Profit = self.round_to((self.enter_price - enter_price) * abs(self.pos), self.min_price) 417 | 418 | if self.HYJ_jd_ss == -11: 419 | self.HYJ_jd_ss_old = -1 420 | self.stop_price = 0 421 | res_sell = self.buy(enter_price, abs(self.pos), mark=True) # 平空 422 | self.HYJ_jd_ss = 0 423 | HYJ_jd_first = "趋势反转平空:交易对:%s,最大亏损:%s,最大利润:%s,当前利润:%s,仓位:%s" % ( 424 | self.symbol, self.lowProfit, self.maxunRealizedProfit, self.unRealizedProfit, self.pos) 425 | self.pos = 0 426 | HYJ_jd_remark = "趋势反转平空:%s,最新价:%s,最高价:%s,最低价:%s" % ( 427 | Profit, self.last_price, self.high_price, self.low_price) 428 | HYJ_jd_tradeType = "平空" 429 | HYJ_jd_curAmount = "%s" % self.enter_price 430 | self.stoploss_price = 0 431 | self.takeprofit_price = 0 432 | self.enter_price = 0 433 | self.high_price = 0 434 | self.low_price = 0 435 | self.maxunRealizedProfit = 0 436 | self.unRealizedProfit = 0 437 | self.lowProfit = 0 438 | self.sync_data() 439 | dingding(f"趋势反转平空,交易所返回:{res_sell}", symbols=self.symbol) 440 | wx_send_msg(HYJ_jd_first, HYJ_jd_tradeType, HYJ_jd_curAmount, HYJ_jd_remark) 441 | elif self.HYJ_jd_ss == -22: 442 | self.HYJ_jd_ss_old = -1 443 | self.stop_price = 0 444 | res_sell = self.buy(enter_price, abs(self.pos), mark=True) # 平空 445 | self.HYJ_jd_ss = 0 446 | HYJ_jd_first = "趋势收缩平空:交易对:%s,最大亏损:%s,最大利润:%s,当前利润:%s,仓位:%s" % ( 447 | self.symbol, self.lowProfit, self.maxunRealizedProfit, self.unRealizedProfit, self.pos) 448 | self.pos = 0 449 | HYJ_jd_remark = "趋势收缩平空:%s,最新价:%s,最高价:%s,最低价:%s" % ( 450 | Profit, self.last_price, self.high_price, self.low_price) 451 | HYJ_jd_tradeType = "平空" 452 | HYJ_jd_curAmount = "%s" % self.enter_price 453 | self.stoploss_price = 0 454 | self.takeprofit_price = 0 455 | self.enter_price = 0 456 | self.high_price = 0 457 | self.low_price = 0 458 | self.maxunRealizedProfit = 0 459 | self.unRealizedProfit = 0 460 | self.lowProfit = 0 461 | self.sync_data() 462 | dingding(f"趋势收缩平空,交易所返回:{res_sell}", symbols=self.symbol) 463 | wx_send_msg(HYJ_jd_first, HYJ_jd_tradeType, HYJ_jd_curAmount, HYJ_jd_remark) 464 | 465 | elif self.stoploss_price != 0 and self.last_price > self.stoploss_price: 466 | self.HYJ_jd_ss_old = -1 467 | self.stop_price = 0 468 | res_sell = self.buy(enter_price, abs(self.pos), mark=True) # 平空 469 | self.HYJ_jd_ss = 0 470 | self.times += 1 # 这个是连续亏损计数 471 | 472 | HYJ_jd_first = "止损平空:交易对:%s,最大亏损:%s,最大利润:%s,当前利润:%s,仓位:%s" % ( 473 | self.symbol, self.lowProfit, self.maxunRealizedProfit, self.unRealizedProfit, self.pos) 474 | self.pos = 0 475 | HYJ_jd_remark = "止损:%s,最新价:%s,最高价:%s,最低价:%s" % ( 476 | Profit, self.last_price, self.high_price, self.low_price) 477 | HYJ_jd_tradeType = "平空" 478 | HYJ_jd_curAmount = "%s" % self.enter_price 479 | self.stoploss_price = 0 480 | self.takeprofit_price = 0 481 | self.enter_price = 0 482 | self.high_price = 0 483 | self.low_price = 0 484 | self.maxunRealizedProfit = 0 485 | self.unRealizedProfit = 0 486 | self.lowProfit = 0 487 | self.sync_data() 488 | dingding(f"止损平空,交易所返回:{res_sell}") 489 | wx_send_msg(HYJ_jd_first, HYJ_jd_tradeType, HYJ_jd_curAmount, HYJ_jd_remark) 490 | 491 | elif self.takeprofit_price > self.last_price: 492 | self.HYJ_jd_ss_old = -1 493 | res_sell = self.buy(enter_price, abs(self.pos), mark=True) # 平空 494 | self.HYJ_jd_ss = 0 495 | HYJ_jd_first = "止盈A:交易对:%s,最大亏损:%s,最大利润:%s,当前利润:%s,仓位:%s" % ( 496 | self.symbol, self.lowProfit, self.maxunRealizedProfit, self.unRealizedProfit, self.pos) 497 | self.pos = 0 498 | HYJ_jd_tradeType = "平空" 499 | HYJ_jd_curAmount = "%s" % self.enter_price 500 | HYJ_jd_remark = "净利:%s,最新价:%s,最高价:%s,最低价:%s" % ( 501 | Profit, self.last_price, self.high_price, self.low_price) 502 | self.times = 0 503 | self.stoploss_price = 0 504 | self.takeprofit_price = 0 505 | self.stop_price = 0 506 | self.enter_price = 0 507 | self.high_price = 0 508 | self.low_price = 0 509 | self.maxunRealizedProfit = 0 510 | self.unRealizedProfit = 0 511 | self.lowProfit = 0 512 | self.sync_data() 513 | dingding(f"空单,止盈A,交易所返回:{res_sell}") 514 | wx_send_msg(HYJ_jd_first, HYJ_jd_tradeType, HYJ_jd_curAmount, HYJ_jd_remark) 515 | 516 | # elif self.unRealizedProfit > 0.1 and self.last_price - self.low_price > 1: 517 | # 518 | # self.HYJ_jd_ss_old = -1 519 | # res_sell = self.buy(enter_price, abs(self.pos)) # 平空 520 | # self.HYJ_jd_ss = 0 521 | # HYJ_jd_first = "止盈B:交易对:%s,最大亏损:%s,最大利润:%s,当前利润:%s,仓位:%s" % ( 522 | # self.symbol, self.lowProfit, self.maxunRealizedProfit, self.unRealizedProfit, self.pos) 523 | # self.pos = 0 524 | # HYJ_jd_tradeType = "平空" 525 | # HYJ_jd_curAmount = "%s" % self.enter_price 526 | # HYJ_jd_remark = "净利:%s,最新价:%s,最高价:%s,最低价:%s" % ( 527 | # Profit, self.last_price, self.high_price, self.low_price) 528 | # self.times = 0 529 | # self.stoploss_price = 0 530 | # self.takeprofit_price = 0 531 | # self.stop_price = 0 532 | # self.enter_price = 0 533 | # self.high_price = 0 534 | # self.low_price = 0 535 | # self.maxunRealizedProfit = 0 536 | # self.unRealizedProfit = 0 537 | # self.lowProfit = 0 538 | # self.sync_data() 539 | # dingding(f"空单,止盈B,交易所返回:{res_sell}") 540 | # wx_send_msg(HYJ_jd_first, HYJ_jd_tradeType, HYJ_jd_curAmount, HYJ_jd_remark) 541 | # 542 | # elif self.unRealizedProfit > 0.05 and self.last_price - self.low_price > 1: 543 | # 544 | # self.HYJ_jd_ss_old = -1 545 | # res_sell = self.buy(enter_price, abs(self.pos)) # 平空 546 | # self.HYJ_jd_ss = 0 547 | # HYJ_jd_first = "止盈C:交易对:%s,最大亏损:%s,最大利润:%s,当前利润:%s,仓位:%s" % ( 548 | # self.symbol, self.lowProfit, self.maxunRealizedProfit, self.unRealizedProfit, self.pos) 549 | # self.pos = 0 550 | # HYJ_jd_tradeType = "平空" 551 | # HYJ_jd_curAmount = "%s" % self.enter_price 552 | # HYJ_jd_remark = "净利:%s,最新价:%s,最高价:%s,最低价:%s" % ( 553 | # Profit, self.last_price, self.high_price, self.low_price) 554 | # self.times = 0 555 | # self.stoploss_price = 0 556 | # self.takeprofit_price = 0 557 | # self.stop_price = 0 558 | # self.enter_price = 0 559 | # self.high_price = 0 560 | # self.low_price = 0 561 | # self.maxunRealizedProfit = 0 562 | # self.unRealizedProfit = 0 563 | # self.lowProfit = 0 564 | # self.sync_data() 565 | # dingding(f"空单,止盈C,交易所返回:{res_sell}") 566 | # wx_send_msg(HYJ_jd_first, HYJ_jd_tradeType, HYJ_jd_curAmount, HYJ_jd_remark) 567 | # 568 | # elif self.maxunRealizedProfit > 0.1 and self.last_price - self.low_price > 2: 569 | # 570 | # self.HYJ_jd_ss_old = -1 571 | # res_sell = self.buy(enter_price, abs(self.pos)) # 平空 572 | # self.HYJ_jd_ss = 0 573 | # HYJ_jd_first = "止盈D:交易对:%s,最大亏损:%s,最大利润:%s,当前利润:%s,仓位:%s" % ( 574 | # self.symbol, self.lowProfit, self.maxunRealizedProfit, self.unRealizedProfit, self.pos) 575 | # self.pos = 0 576 | # HYJ_jd_tradeType = "平空" 577 | # HYJ_jd_curAmount = "%s" % self.enter_price 578 | # HYJ_jd_remark = "净利:%s,最新价:%s,最高价:%s,最低价:%s" % ( 579 | # Profit, self.last_price, self.high_price, self.low_price) 580 | # self.times = 0 581 | # self.stoploss_price = 0 582 | # self.takeprofit_price = 0 583 | # self.stop_price = 0 584 | # self.enter_price = 0 585 | # self.high_price = 0 586 | # self.low_price = 0 587 | # self.maxunRealizedProfit = 0 588 | # self.unRealizedProfit = 0 589 | # self.lowProfit = 0 590 | # self.sync_data() 591 | # dingding(f"空单,止盈D,交易所返回:{res_sell}") 592 | # wx_send_msg(HYJ_jd_first, HYJ_jd_tradeType, HYJ_jd_curAmount, HYJ_jd_remark) 593 | # 594 | # elif self.maxunRealizedProfit > 0.05 and self.last_price - self.low_price > 2: 595 | # 596 | # self.HYJ_jd_ss_old = -1 597 | # res_sell = self.buy(enter_price, abs(self.pos)) # 平空 598 | # self.HYJ_jd_ss = 0 599 | # HYJ_jd_first = "止盈E:交易对:%s,最大亏损:%s,最大利润:%s,当前利润:%s,仓位:%s" % ( 600 | # self.symbol, self.lowProfit, self.maxunRealizedProfit, self.unRealizedProfit, self.pos) 601 | # self.pos = 0 602 | # HYJ_jd_tradeType = "平空" 603 | # HYJ_jd_curAmount = "%s" % self.enter_price 604 | # HYJ_jd_remark = "净利:%s,最新价:%s,最高价:%s,最低价:%s" % ( 605 | # Profit, self.last_price, self.high_price, self.low_price) 606 | # self.times = 0 607 | # self.stoploss_price = 0 608 | # self.takeprofit_price = 0 609 | # self.stop_price = 0 610 | # self.enter_price = 0 611 | # self.high_price = 0 612 | # self.low_price = 0 613 | # self.maxunRealizedProfit = 0 614 | # self.unRealizedProfit = 0 615 | # self.lowProfit = 0 616 | # self.sync_data() 617 | # dingding(f"空单,止盈E,交易所返回:{res_sell}") 618 | # wx_send_msg(HYJ_jd_first, HYJ_jd_tradeType, HYJ_jd_curAmount, HYJ_jd_remark) 619 | --------------------------------------------------------------------------------