220 lines
7.2 KiB
Python
220 lines
7.2 KiB
Python
# -*- coding: utf-8 -*-
|
|
import abc
|
|
import datetime
|
|
import re,json
|
|
import time
|
|
from typing import List
|
|
import requests
|
|
from log import logger
|
|
from misc import parse_cookies_str
|
|
|
|
|
|
class BaseFollower(metaclass=abc.ABCMeta):
|
|
"""
|
|
slippage: 滑点,取值范围为 [0, 1]
|
|
"""
|
|
|
|
LOGIN_PAGE = ""
|
|
LOGIN_API = ""
|
|
TRANSACTION_API = ""
|
|
CMD_CACHE_FILE = "cmd_cache.pk"
|
|
WEB_REFERER = ""
|
|
WEB_ORIGIN = ""
|
|
|
|
def __init__(self):
|
|
#self.trade_queue = queue.Queue()
|
|
#self.expired_cmds = set()
|
|
|
|
self.s = requests.Session()
|
|
self.s.verify = False
|
|
|
|
self.slippage: float = 0.0
|
|
|
|
def login(self, user=None, password=None, **kwargs):
|
|
"""
|
|
雪球登陆, 需要设置 cookies
|
|
:param cookies: 雪球登陆需要设置 cookies, 具体见
|
|
https://smalltool.github.io/2016/08/02/cookie/
|
|
:return:
|
|
"""
|
|
cookies = kwargs.get("cookies")
|
|
|
|
if cookies is None:
|
|
raise TypeError(
|
|
"雪球登陆需要设置 cookies, 具体见" "https://smalltool.github.io/2016/08/02/cookie/"
|
|
)
|
|
headers = self._generate_headers()
|
|
self.s.headers.update(headers)
|
|
|
|
self.s.get(self.LOGIN_PAGE)
|
|
|
|
cookie_dict = parse_cookies_str(cookies)
|
|
self.s.cookies.update(cookie_dict)
|
|
#extract_strategy_name(self, 'ZH1332574')
|
|
logger.info("登录成功")
|
|
|
|
def _generate_headers(self):
|
|
headers = {
|
|
"Accept": "application/json, text/javascript, */*; q=0.01",
|
|
"Accept-Encoding": "gzip, deflate, br",
|
|
"Accept-Language": "en-US,en;q=0.8",
|
|
"User-Agent": "Mozilla/5.0 (X11; Linux x86_64) "
|
|
"AppleWebKit/537.36 (KHTML, like Gecko) "
|
|
"Chrome/54.0.2840.100 Safari/537.36",
|
|
"Referer": self.WEB_REFERER,
|
|
"X-Requested-With": "XMLHttpRequest",
|
|
"Origin": self.WEB_ORIGIN,
|
|
"Content-Type": "application/x-www-form-urlencoded; charset=UTF-8",
|
|
}
|
|
return headers
|
|
|
|
def check_login_success(self, rep):
|
|
"""检查登录状态是否成功
|
|
:param rep: post login 接口返回的 response 对象
|
|
:raise 如果登录失败应该抛出 NotLoginError """
|
|
pass
|
|
|
|
def create_login_params(self, user, password, **kwargs) -> dict:
|
|
"""生成 post 登录接口的参数
|
|
:param user: 用户名
|
|
:param password: 密码
|
|
:return dict 登录参数的字典
|
|
"""
|
|
return {}
|
|
|
|
|
|
|
|
def extract_strategy_name(self, strategy_url):
|
|
"""
|
|
抽取 策略名,主要用于日志打印,便于识别
|
|
:param strategy_url:
|
|
:return: str 策略名
|
|
"""
|
|
pass
|
|
#新增
|
|
def _query_zh_(self,userid):
|
|
|
|
url = 'https://im.xueqiu.com/im-comet/v2/sessions/1681984443-0/messages.json?user_id=%s&limit=%d' %(userid, 1)
|
|
chat_history = self.s.get(url).json()
|
|
for chat_record in chat_history:
|
|
new=chat_record['messageId']#获取messageId
|
|
messageType=chat_record['messageType']#获取messageId
|
|
starte='1'
|
|
if messageType=='VIEW':
|
|
view1 = json.loads(chat_record['view'])#策略代号
|
|
starte=view1['url'][21:] #策略代号
|
|
time.sleep(1)
|
|
|
|
return new,starte
|
|
|
|
#非开盘时间调仓,补充
|
|
def minutes_2(self, strategys, userid, assets,**kwargs):
|
|
dayOfWeek = datetime.datetime.now().weekday()
|
|
time_n=datetime.datetime.now()
|
|
hour=str(time_n)[11:13]
|
|
minute=int(str(time_n)[14:16])
|
|
print(time_n)
|
|
if dayOfWeek<=4 and ((hour=='09' and minute<32 and minute>=30) or (hour=='13' and minute<2)) :
|
|
#if dayOfWeek<=6 or (hour=='11' or minute<=59):
|
|
for j in range(0,len(strategys)):
|
|
print('开盘自动监测中......',strategys[j])
|
|
try:
|
|
transactions = self.query_strategy_transaction(strategys[j], assets[j],**kwargs)
|
|
if len(transactions)>0:
|
|
return transactions
|
|
except Exception as e:
|
|
#logger.exception("无法获取策略 %s 调仓信息, 错误: %s, 跳过此次调仓查询", name, e)
|
|
time.sleep(3)
|
|
if j < len(strategys)-1:
|
|
continue
|
|
else:
|
|
return []
|
|
else:
|
|
return []
|
|
|
|
def track_strategy_worker(self, strategys, userid,users, assets, interval=10, **kwargs):
|
|
|
|
"""跟踪下单worker
|
|
:param strategy: 策略id
|
|
:param name: 策略名字
|
|
:param interval: 轮询策略的时间间隔,单位为秒"""
|
|
old,starte=self._query_zh_(userid)
|
|
|
|
transactions=[]
|
|
k=0
|
|
while True:
|
|
k=k+1
|
|
print(k)
|
|
if k>=100:
|
|
return []
|
|
|
|
#前两分钟补充,非开盘调仓
|
|
minutes_2_data=self.minutes_2( strategys, userid, assets,**kwargs)
|
|
if not minutes_2_data is None and len(minutes_2_data)>0:
|
|
return minutes_2_data
|
|
|
|
try:
|
|
new,starte_n=self._query_zh_(userid)#新增
|
|
except:
|
|
time.sleep(5)
|
|
|
|
for j in range(0,len(strategys)):
|
|
print('自动监测中......',strategys[j])
|
|
if new != old and starte_n==strategys[j]:
|
|
#if new == old:
|
|
old=new
|
|
try:
|
|
transactions = self.query_strategy_transaction(strategys[j], assets[j],**kwargs)
|
|
|
|
if len(transactions)>0:
|
|
k=5
|
|
return transactions
|
|
if k==5:
|
|
break
|
|
|
|
except Exception as e:
|
|
logger.exception("无法获取策略 %s 调仓信息, 错误: %s, 跳过此次调仓查询", e)
|
|
time.sleep(3)
|
|
continue
|
|
|
|
|
|
|
|
def query_strategy_transaction(self, strategy,assets, **kwargs):
|
|
|
|
params = self.create_query_transaction_params(strategy)
|
|
|
|
rep = self.s.get(self.TRANSACTION_API, params=params)
|
|
|
|
history = rep.json()
|
|
|
|
transactions = self.extract_transactions(history)
|
|
|
|
return self.project_transactions(transactions,assets, **kwargs)
|
|
|
|
|
|
def extract_transactions(self, history) -> List[str]:
|
|
"""
|
|
抽取接口返回中的调仓记录列表
|
|
:param history: 调仓接口返回信息的字典对象
|
|
:return: [] 调参历史记录的列表
|
|
"""
|
|
return []
|
|
|
|
def create_query_transaction_params(self, strategy) -> dict:
|
|
"""
|
|
生成用于查询调参记录的参数
|
|
:param strategy: 策略 id
|
|
:return: dict 调参记录参数
|
|
"""
|
|
return {}
|
|
|
|
|
|
def project_transactions(self, transactions, **kwargs):
|
|
|
|
"""
|
|
修证调仓记录为内部使用的统一格式
|
|
:param transactions: [] 调仓记录的列表
|
|
:return: [] 修整后的调仓记录
|
|
"""
|
|
pass
|