Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -108,3 +108,12 @@ venv.bak/

# vscode
.vscode/

# history plugin
.history/

# My test
tests/test_main.py

# MacOS
.DS_Store
4 changes: 2 additions & 2 deletions pysnowball/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@

from pysnowball.token import (get_token,set_token)

from pysnowball.user import(watch_list, watch_stock)
from pysnowball.user import(watch_list, watch_stock, watch_funds)

from pysnowball.cube import(nav_daily, rebalancing_history, rebalancing_current, quote_current)

Expand All @@ -34,6 +34,6 @@

from pysnowball.fund import (fund_detail, fund_info, fund_growth,
fund_nav_history, fund_derived, fund_asset,
fund_manager, fund_achievement, fund_trade_date)
fund_manager, fund_achievement, fund_trade_date, fund_yield, fund_search, fund_exist, funds_add, funds_remove)

from pysnowball.suggest import suggest_stock
31 changes: 21 additions & 10 deletions pysnowball/api_ref.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@
# user
watch_list = "https://stock.xueqiu.com/v5/stock/portfolio/list.json?system=true"
watch_stock = "https://stock.xueqiu.com/v5/stock/portfolio/stock/list.json?size=1000&category=1&pid="
watch_funds = "https://stock.xueqiu.com/v5/stock/portfolio/stock/list.json?size=1000&category=2&pid="

# cube
nav_daily = "https://xueqiu.com/cubes/nav_daily/all.json?cube_symbol="
Expand All @@ -64,24 +65,34 @@

# fund
# param is fund code
fund_detail = "https://danjuanapp.com/djapi/fund/detail/%s"
fund_detail = "https://danjuanfunds.com/djapi/fund/detail/%s"
# param is fund code
fund_info = "https://danjuanapp.com/djapi/fund/%s"
fund_info = "https://danjuanfunds.com/djapi/fund/%s"
# first param is fund code, second is 'ty'
fund_growth = "https://danjuanapp.com/djapi/fund/growth/%s?day=%s"
fund_growth = "https://danjuanfunds.com/djapi/fund/growth/%s?day=%s"
# first param is fund code
fund_nav_history = "https://danjuanapp.com/djapi/fund/nav/history/%s?page=%s&size=%s"
fund_nav_history = "https://danjuanfunds.com/djapi/fund/nav/history/%s?page=%s&size=%s"
# param is fund code
fund_achievement = "https://danjuanapp.com/djapi/fundx/base/fund/achievement/%s"
fund_achievement = "https://danjuanfunds.com/djapi/fundx/base/fund/achievement/%s"
# 基金持仓:param is fund code
fund_asset = "https://danjuanapp.com/djapi/fundx/base/fund/record/asset/percent?fund_code=%s"
fund_asset = "https://danjuanfunds.com/djapi/fundx/base/fund/record/asset/percent?fund_code=%s"
# 基金管理人: param is fund code
fund_manager = "https://danjuanapp.com/djapi/fundx/base/fund/record/manager/list?fund_code=%s&post_status=%s"
# https://danjuanapp.com/djapi/fund/base/quote/data/index/analysis/008975
fund_manager = "https://danjuanfunds.com/djapi/fundx/base/fund/record/manager/list?fund_code=%s&post_status=%s"
# https://danjuanfunds.com/djapi/fund/base/quote/data/index/analysis/008975
# param is fund code
fund_trade_date = "https://danjuanapp.com/djapi/fund/order/v2/trade_date?fd_code=%s"
fund_trade_date = "https://danjuanfunds.com/djapi/fund/order/v2/trade_date?fd_code=%s"
# param is fund code
fund_derived = "https://danjuanapp.com/djapi/fund/derived/%s"
fund_derived = "https://danjuanfunds.com/djapi/fund/derived/%s"
# Yield info: param is fund code
fund_yield = "https://danjuanfunds.com/djapi/fundx/autoinvest/quote/yield/list?fd_code=%s"
# Fund search: params are keyword and cookie
fund_search = "https://danjuanfunds.com/djapi/v2/search?key=%s&xq_access_token=&source=index"
# Fund does exist in watchlist: param is fund code
fund_exist = "https://danjuanfunds.com/xqstock/v5/stock/portfolio/stock/hasexist.json?symbol=%s"
# POST: Add to watchlist
funds_add = "https://danjuanfunds.com/xqstock/v5/stock/portfolio/stock/add.json"
# POST: Remove from watchlist
funds_remove = "https://danjuanfunds.com/xqstock/v5/stock/portfolio/stock/cancel.json"

# suggest
suggest_stock = "https://xueqiu.com/query/v1/suggest_stock.json?q="
39 changes: 39 additions & 0 deletions pysnowball/fund.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,10 @@ def fund_info(fund_code):


def fund_growth(fund_code, day='ty'):
'''
Args:
day: 'ty' (default) - this year,'1m','3m','6m','1y','2y','3y','5y','all'
'''
return utls.fetch_danjuan_fund(api_ref.fund_growth % (fund_code, day))


Expand All @@ -36,3 +40,38 @@ def fund_trade_date(fund_code):

def fund_derived(fund_code):
return utls.fetch_danjuan_fund(api_ref.fund_derived % fund_code)

def fund_yield(fund_code):
return utls.fetch_danjuan_fund(api_ref.fund_yield % fund_code)

def fund_search(keywords):
return utls.fetch_danjuan_fund(api_ref.fund_search % keywords)

def fund_exist(fund_code):
return utls.fetch_danjuan_fund(api_ref.fund_exist % (fund_code if fund_code.startswith('F') else 'F'+fund_code))

def funds_add(fund_codes):
''' Add fund(s) to watch list
Args:
fund_codes: list of fund codes, e.g. ['F019918','F161039']
'''
payload = "symbols="
for code in fund_codes:
if not code.startswith('F'):
code = 'F' + code
payload += code + ','
payload = payload if not payload.endswith(',') else payload[:-1]
return utls.post_danjuan_fund(api_ref.funds_add, payload)

def funds_remove(fund_codes):
''' Remove fund(s) from watch list
Args:
fund_codes: list of fund codes, e.g. ['F019918','F161039']
'''
payload = "symbols="
for code in fund_codes:
if not code.startswith('F'):
code = 'F' + code
payload += code + ','
payload = payload if not payload.endswith(',') else payload[:-1]
return utls.post_danjuan_fund(api_ref.funds_remove, payload)
12 changes: 9 additions & 3 deletions pysnowball/realtime.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,12 @@ def pankou(symbol):
url = api_ref.realtime_pankou+symbol
return utls.fetch(url)


def kline(symbol,period='day',count=284):
return utls.fetch(api_ref.kline.format(symbol, int(time.time()*1000), period, count))
def kline(symbol,begin=int(time.time()*1000),period='day',count=284):
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

参数能不能换个顺序,来保持低版本的兼容性

''' Get kline data
Args:
symbol: stock symbol, e.g. 'SZ000001'
begain: timestamp in milliseconds = int(time.time()*1000), default current time
count: number of data points to fetch, default 284 (fetch all available data)
period: '1m', '5m', '15m', '30m', '60m', 'day', 'week', 'month', 'quarter','year'
'''
return utls.fetch(api_ref.kline.format(symbol, begin, period, count))
12 changes: 11 additions & 1 deletion pysnowball/token.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,16 @@ def get_token():
else:
return os.environ['XUEQIUTOKEN']

def set_token(token):
def get_danjuan_token():
if os.environ.get('DANJUANTOKEN') is None:
raise Exception(cons.NOTOKEN_ERROR_MSG)
else:
return os.environ['DANJUANTOKEN']

def set_token(token,danjuantoken=None):
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

如果一个token就能用,咱就不搞两套了。都用token,不引入复杂性。

os.environ['XUEQIUTOKEN'] = token
if danjuantoken:
os.environ['DANJUANTOKEN'] = danjuantoken
else:
os.environ['DANJUANTOKEN'] = token
return os.environ['XUEQIUTOKEN']
4 changes: 4 additions & 0 deletions pysnowball/user.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,8 @@ def watch_list():

def watch_stock(id):
url = api_ref.watch_stock + str(id)
return utls.fetch(url)

def watch_funds(id):
url = api_ref.watch_funds + str(id)
return utls.fetch(url)
29 changes: 25 additions & 4 deletions pysnowball/utls.py
Original file line number Diff line number Diff line change
Expand Up @@ -114,14 +114,35 @@ def fetch_hkc(url, txt_date=None):
return response.content


def fetch_danjuan_fund(url):
fund_header = {
'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.107 Safari/537.36',
}
def fetch_danjuan_fund(url,host="danjuanfunds.com"):
fund_header = {'Host': host,
'Accept': 'application/json',
'Cookie': token.get_danjuan_token(),
'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/139.0.0.0 Safari/537.36',
'Accept-Language': 'zh-Hans-CN;q=1, ja-JP;q=0.9',
'Accept-Encoding': 'br, gzip, deflate',
'Connection': 'keep-alive'}

response = requests.request(method="GET", url=url, headers=fund_header)

if response.status_code != 200:
raise Exception(response.content)

return response.json()

def post_danjuan_fund(url, payload, host="danjuanfunds.com"):
fund_header = {'Host': host,
'Accept': 'application/json',
'Content-Type': 'application/x-www-form-urlencoded',
'Cookie': token.get_danjuan_token(),
'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/139.0.0.0 Safari/537.36',
'Accept-Language': 'zh-Hans-CN;q=1, ja-JP;q=0.9',
'Accept-Encoding': 'br, gzip, deflate',
'Connection': 'keep-alive'}

response = requests.post(url, headers=fund_header, data=payload)

if response.status_code != 200:
raise Exception(response.content)

return response.json()