119 lines
4.0 KiB
Python
119 lines
4.0 KiB
Python
# -*- coding: utf-8 -*-
|
|
from __future__ import division, print_function, unicode_literals
|
|
from datetime import datetime
|
|
from follower import BaseFollower
|
|
from log import logger
|
|
from misc import parse_cookies_str
|
|
import pandas as pd
|
|
|
|
class XueQiuFollower(BaseFollower):
|
|
LOGIN_PAGE = "https://www.xueqiu.com"
|
|
LOGIN_API = "https://xueqiu.com/snowman/login"
|
|
TRANSACTION_API = "https://xueqiu.com/cubes/rebalancing/history.json"
|
|
PORTFOLIO_URL = "https://xueqiu.com/p/"
|
|
WEB_REFERER = "https://www.xueqiu.com"
|
|
|
|
def __init__(self):
|
|
super().__init__()
|
|
self._adjust_sell = None
|
|
self._users = None
|
|
|
|
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 extract_strategy_name(self, strategy_url):
|
|
|
|
base_url = "https://xueqiu.com/cubes/nav_daily/all.json?cube_symbol={}"
|
|
url = base_url.format(strategy_url)
|
|
rep = self.s.get(url)
|
|
|
|
info_index = 0
|
|
return rep.json()[info_index]["name"]
|
|
|
|
|
|
def extract_transactions(self, history):
|
|
|
|
if history["count"] <= 0:
|
|
return []
|
|
rebalancing_index = 0
|
|
raw_transactions = history["list"][rebalancing_index]["rebalancing_histories"]
|
|
transactions = []
|
|
for transaction in raw_transactions:
|
|
if transaction["price"] is None:
|
|
logger.info("该笔交易无法获取价格,疑似未成交,跳过。交易详情: %s", transaction)
|
|
continue
|
|
transactions.append(transaction)
|
|
|
|
|
|
return transactions
|
|
|
|
def create_query_transaction_params(self, strategy):
|
|
params = {"cube_symbol": strategy, "page": 1, "count": 1}
|
|
return params
|
|
|
|
# noinspection PyMethodOverriding
|
|
def none_to_zero(self, data):
|
|
if data is None:
|
|
return 0
|
|
return data
|
|
|
|
# noinspection PyMethodOverriding
|
|
def project_transactions(self, transactions, assets):
|
|
|
|
pa = pd.DataFrame(index=[],columns=[])
|
|
for transaction in transactions:
|
|
weight_diff = self.none_to_zero(transaction["weight"]) - self.none_to_zero(
|
|
transaction["prev_weight"]
|
|
)
|
|
#print(33333,weight_diff,assets,transaction["price"])
|
|
initial_amount = abs(weight_diff) / 100 * assets / transaction["price"]
|
|
|
|
transaction["datetime"] = datetime.fromtimestamp(
|
|
transaction["created_at"] // 1000
|
|
)
|
|
|
|
transaction["stock_code"] = transaction["stock_symbol"].lower()
|
|
|
|
transaction["action"] = "buy" if weight_diff > 0 else "sell"
|
|
|
|
if str(transaction["stock_code"][2:4])=='11' or str(transaction["stock_code"][2:4])=='12':
|
|
shou=1
|
|
else:
|
|
shou=2
|
|
transaction["amount"] = int(round(initial_amount, -shou))
|
|
|
|
pa.loc[transaction["stock_code"],"price"]=transaction["price"]
|
|
pa.loc[transaction["stock_code"],"amount"]=transaction["amount"]
|
|
pa.loc[transaction["stock_code"],"datetime"]=transaction["datetime"]
|
|
pa.loc[transaction["stock_code"],"action"]=transaction["action"]
|
|
current_time = datetime.now()
|
|
diff = (current_time - transaction["datetime"]).total_seconds()
|
|
if int(diff)<20:
|
|
return pa
|
|
else:
|
|
return []
|
|
|
|
|