def test_mfundinfo(): zogqb.bcmkset(xa.cashinfo()) assert round(zogqb.total_annualized_returns('2018-08-01'), 3) == 0.036 with pytest.raises(FundTypeError) as excinfo: xa.fundinfo("001211") assert str(excinfo.value ) == "This code seems to be a mfund, use mfundinfo instead"
def test_customize_fee(): df = pd.DataFrame( {"date": ["2020-05-28", "2020-06-01"], "519732": [500.005, -0.505]} ) df["date"] = pd.to_datetime(df["date"]) dqzf = xa.trade(xa.fundinfo("519732"), df) assert dqzf.dailyreport("2020-06-02")["基金分红与赎回"].iloc[0] == 2.22 assert dqzf.dailyreport("2020-05-31")["持有份额"].iloc[0] == 116.5 # issue 59 df = pd.DataFrame( {"date": ["2020-05-28", "2020-06-01"], "519732": [10000.005, -0.505]} ) df["date"] = pd.to_datetime(df["date"]) dqzf = xa.trade(xa.fundinfo("519732"), df) assert round(dqzf.dailyreport("2020-05-28").iloc[0]["基金现值"], 0) == 10000.0
def test_fund_update(): zghl = xa.fundinfo("164906", **ioconf) len1 = len(zghl.price) delete_csvlines(path=ioconf["path"] + "164906.csv", lines=83) zghl = xa.fundinfo("164906", **ioconf) len2 = len(zghl.price) assert len1 == len2 jxzl = xa.mfundinfo("002758", **ioconf) netvalue = jxzl.price.iloc[-1]["netvalue"] len3 = len(jxzl.price) delete_csvlines(path=ioconf["path"] + "002758.csv", lines=9) jxzl = xa.mfundinfo("002758", **ioconf) netvalue2 = jxzl.price.iloc[-1]["netvalue"] len4 = len(jxzl.price) assert len3 == len4 assert round(netvalue, 4) == round(netvalue2, 4)
def test_fund(): assert hs300.round_label == 1 assert hs300.name == "景顺长城沪深300指数增强" ## "景顺长城沪深300增强", 蜜汁改名。。。 assert hs300.fenhongdate[1] == pd.Timestamp("2017-08-15") assert hs300.get_holdings(2019, 4).iloc[0]["name"] == "中国平安" assert ( float(hs300.special[hs300.special["date"] == "2017-08-04"]["comment"]) == 0.19 ) hs300.rate = 0.12 hs300.segment = [[0, 7], [7, 365], [365, 730], [730]] with pytest.raises(Exception) as excinfo: hs300.shuhui( 100, "2014-01-04", [[pd.Timestamp("2014-01-03"), 200], [pd.Timestamp("2017-01-03"), 200]], ) assert str(excinfo.value) == "One cannot move share before the lastest operation" assert ( hs300.shuhui( 320, "2018-01-01", [[pd.Timestamp("2011-01-03"), 200], [pd.Timestamp("2017-12-29"), 200]], )[1] == 685.72 ) assert hs300.shengou(200, "2018-07-20")[2] == 105.24 with pytest.raises(FundTypeError) as excinfo: xa.mfundinfo("000311") assert str(excinfo.value) == "This code seems to be a fund, use fundinfo instead" hs300.info() dax = xa.fundinfo("510030") # test empty shuhuifei and shengoufei case assert dax.feeinfo == ["小于7天", "1.50%", "大于等于7天", "0.00%"]
def index(request): code = request.GET.get('code') try: zzcm = xa.fundinfo(code) except Exception: return JsonResponse({'code': 500, 'msg': '基金代码错误'}) # 分红再投入 zzcm.dividend_label = 1 orgin_start = request.GET.get('start') orgin_end = request.GET.get('end') amount = request.GET.get('amount') freq = request.GET.get('freq') offset = request.GET.get('offset') start = datetime.strptime(orgin_start, '%Y-%m-%d') end = datetime.strptime(orgin_end, '%Y-%m-%d') new_start = start - timedelta(days=100) new_end = end + timedelta(days=100) rng = pd.date_range(new_start, new_end, freq=freq) + \ pd.DateOffset(days=int(offset)) rng = rng[rng <= end] # 过滤超出范围的日期 rng = rng[rng >= start] price = zzcm.price[(zzcm.price["date"] >= start) & (zzcm.price["date"] <= end)] # 有价格的起始日期 priceStart = price.iloc[0].date priceEnd = price.iloc[-1].date # 需要判断rng的时间是否合法,是否都在有价格的区间 datel = [] isSmall = False for date in rng: if date >= priceStart and date <= priceEnd: datel.append(date) elif date < priceStart: isSmall = True if isSmall: try: thing_index = datel.index(priceStart) except ValueError: thing_index = -1 if thing_index == -1: datel.insert(0, priceStart) status = pd.DataFrame(data={ "date": datel, zzcm.code: [float(amount)] * len(datel) }) cm_t3 = xa.trade(zzcm, status) dailyreport = cm_t3.dailyreport(orgin_end) cftable = cm_t3.cftable del cftable['share'] cftable['date'] = cftable['date'].astype('datetime64[ns]') cash_flow = cftable.values.tolist() fv = dailyreport['基金现值'][0] cash_flow.append([end, fv]) rate = xirr(cash_flow) return JsonResponse({ 'code': 0, 'xirr': rate, 'dailyreport': dailyreport.to_dict() })
def f(trade_info, code): #某个基金的交易信息 fundinfo = xa.fundinfo(code) buy, sell = 0, 0 fe = 0 for index, row in trade_info.iterrows(): date = row.get('date') dwjz = get_jz(code, date) v = row.get(code) if v > 0: # print('申购费率:{}'.format(fundinfo.rate)) buy += v # buy += v else: sell += v fe += v * (1 - fundinfo.rate / 100.) / dwjz #份额变动 要考虑申购费率 last_trade_day = datetime.strftime(datetime.now() - timedelta(1), '%Y-%m-%d') dqjz = get_jz(code, last_trade_day) #api接口到24点以后才更新净值,所以做多只能取到昨日净值 # print(dqjz) dqye = fe * dqjz + sell #包括当前持有金额以及已卖出金额之和 syl = dqye / buy - 1 #收益率 # print('{},{}--份额:{},昨日净值{},当前余额{},总投入{},收益率{},盈利{}'.format(fundinfo.name,last_trade_day,fe,dqjz,dqye,buy,syl,dqye-buy)) print('{},当前余额{:.2f},总投入{:.2f},收益率{:.3f},盈利{:.2f}'.format( fundinfo.name, dqye, buy, syl, dqye - buy)) return (fe, dqjz, dqye, buy, syl)
def test_weekly_price(): # see https://github.com/refraction-ray/xalpha/issues/27 ryjh = xa.fundinfo("008969") bah = xa.policy.buyandhold(ryjh, start="2019-01-01", totmoney=100000) bah.sellout("2020-05-12") # 选定日期全部卖出 jshstrade = xa.trade(ryjh, bah.status) assert round(jshstrade.xirrrate("2020-05-01", startdate="2020-02-01"), 1) == 0.2
def test_csvio(): hs300 = xa.fundinfo('000311', **ioconf) len1 = len(hs300.price) hs300 = xa.fundinfo('000311', **ioconf) len2 = len(hs300.price) delete_csvlines(path=ioconf['path'] + '000311.csv') hs300 = xa.fundinfo('000311', **ioconf) len3 = len(hs300.price) assert len1 == len2 assert len1 == len3 delete_csvlines(path=ioconf['path'] + '001211.csv') zogqb2 = xa.mfundinfo('001211', **ioconf) assert round(zogqb.price.iloc[-1].netvalue, 5) == round(zogqb2.price.iloc[-1].netvalue, 5) delete_csvlines(path=ioconf['path'] + '0000827.csv') zzhb2 = xa.indexinfo('0000827', **ioconf) assert len(zzhb2.price) == len(zzhb.price)
def test_fund_update(): zghl = xa.fundinfo( "501029", **ioconf) # 164906 maybe possible remainning issue for qdii? len1 = len(zghl.price) delete_csvlines(path=ioconf["path"] + "501029.csv", lines=83) zghl = xa.fundinfo("501029", **ioconf) len2 = len(zghl.price) assert len1 == len2 jxzl = xa.mfundinfo("002758", **ioconf) netvalue = jxzl.price.iloc[-1]["netvalue"] len3 = len(jxzl.price) delete_csvlines(path=ioconf["path"] + "002758.csv", lines=9) jxzl = xa.mfundinfo("002758", **ioconf) netvalue2 = jxzl.price.iloc[-1]["netvalue"] len4 = len(jxzl.price) assert len3 == len4 assert round(netvalue, 4) == round(netvalue2, 4)
def test_fund_holdings(): f = xa.fundinfo("F519732") df = f.get_stock_holdings(2020, 2) assert df.iloc[0]["code"] == "300413" d = f.get_industry_holdings(2020, 2) assert d["交通运输"] == 5.48 d = f.get_portfolio_holdings("20180101") assert d["stock_ratio"] == 68.62 df = f.get_bond_holdings(2020, 2) assert df.iloc[0]["code"] == "190307" assert f.which_industry() == "宽基基金"
def test_fund_update(): zghl = xa.fundinfo( "501029", **ioconf) # 164906 maybe possible remainning issue for qdii? len1 = len(zghl.price) delete_csvlines(path=ioconf["path"] + "501029.csv", lines=83) zghl = xa.fundinfo("501029", **ioconf) len2 = len(zghl.price) assert (len1 == len2) or (len1 - len2 == -1) # similar fix up jxzl = xa.mfundinfo("002758", **ioconf) netvalue = jxzl.price.iloc[-1]["netvalue"] len3 = len(jxzl.price) delete_csvlines(path=ioconf["path"] + "002758.csv", lines=9) jxzl = xa.mfundinfo("002758", **ioconf) netvaluel = [ round(jxzl.price.iloc[-1]["netvalue"], 4), round(jxzl.price.iloc[-2]["netvalue"], 4), ] len4 = len(jxzl.price) assert (len3 == len4) or (len3 - len4 == -1) assert round(netvalue, 4) in netvaluel ##天天基金的总量 API 更新越来越慢了。。。
def test_csvio(): hs300 = xa.fundinfo("000311", **ioconf) len1 = len(hs300.price) hs300 = xa.fundinfo("000311", **ioconf) len2 = len(hs300.price) delete_csvlines(path=ioconf["path"] + "000311.csv") hs300 = xa.fundinfo("000311", **ioconf) len3 = len(hs300.price) assert (len1 == len2) or (len1 - len2 == -1) # temp fixup # there may be time lag for update of .js API, i.e. 天天基金的该 API 不一定能保证更新昨天的净值,即使不是 QDII assert (len1 == len3) or (len1 - len3 == -1) delete_csvlines(path=ioconf["path"] + "001211.csv") zogqb2 = xa.mfundinfo("001211", **ioconf) assert round(zogqb.price.iloc[-1].netvalue, 5) in [ round(zogqb2.price.iloc[-1].netvalue, 5), round(zogqb2.price.iloc[-2].netvalue, 5), ] delete_csvlines(path=ioconf["path"] + "0000827.csv") zzhb2 = xa.indexinfo("0000827", **ioconf) assert (len(zzhb2.price) == len( zzhb.price)) or ((len(zzhb2.price) - len(zzhb.price)) == 1)
def get_jz(code, date): fundinfo = xa.fundinfo(code) df = fundinfo.price # print(df) #获取某一日期净值 如果没有则返回最后一个交易日净值 if df[df['date'] == date].empty: dwjz = df.tail(1)['netvalue'] else: dwjz = df[df['date'] == date]['netvalue'] for index in dwjz.index: # print('{},date:{}单位净值为:{}'.format(fundinfo.name,date,dwjz.get(index))) return dwjz.get(index)
def get_fund_history(self): '''下载历史数据 ''' now = datetime.datetime.now() fund_day_start = now + datetime.timedelta(days=-60) fund_day_start = fund_day_start.strftime('%Y-%m-%d') # 获取数据 groups = [] for fund_code in tqdm(self.load(self.SELECT_FUND_LIST_CODE_FILE)): try: fund_data = xa.fundinfo(fund_code, fetch=False, save=False) fund_data.price.reset_index(drop=True, inplace=True) fund_data.rsi(30) fund_data = fund_data.price fund_data.loc[:, "code"] = fund_code fund_data = fund_data.loc[fund_data["date"] >= fund_day_start] group = fund_data group.sort_values("date", inplace=True) group.loc[:, "netvalue"] = (group["netvalue"] - group["netvalue"].shift(periods=1)) / group[ "netvalue"].shift(periods=1) group.dropna(axis=0, inplace=True) group.loc[:, 'MA3'] = group["netvalue"].rolling(window=3).mean() group.sort_values('date', ascending=False, inplace=True) down_count = 0 for ele in group["MA3"]: if ele < 0: down_count += 1 else: break groups.append( (fund_code, down_count, group.loc[group.index[0], "MA3"], group.loc[group.index[0], "RSI30"])) except Exception as e: continue fund_history = pd.DataFrame(groups, columns=['code', 'down_count', 'MA3', 'RSI30']) fund_history.sort_values("down_count", ascending=False, inplace=True) fund_em_fund_name_df = task.load(task.ALL_MARKET_FUND_INFO_FILE) fund_history = fund_history.merge(fund_em_fund_name_df, left_on='code', right_on='基金代码') fund_history = fund_history.loc[:, ['基金代码', '基金简称', '基金类型', 'down_count', 'MA3', 'RSI30']] fund_history = fund_history.loc[ (~fund_history['基金类型'].isin(["债券型", '定开债券'])) & (~fund_history['基金简称'].str.contains("债|年|月|量化"))] joblib.dump(fund_history, self.FUND_HISTORY_DATA_FILE) return self
def get_year_rate(code): last_trade_day = datetime.strftime(datetime.now() - timedelta(1), '%Y-%m-%d') first_day_of_year = '2020-01-02' fake_buy = 10000 #假设买入10000元 b_jz = get_jz(code, first_day_of_year) e_jz = get_jz(code, last_trade_day) buy_fe = fake_buy / b_jz current_money = e_jz * buy_fe fundinfo = xa.fundinfo(code) #考虑分红情况 fenghong = get_fenhong(code) fenghong_zonge = fenghong * buy_fe add = (fenghong_zonge + current_money - fake_buy) / fake_buy # print('{},{},add={}',b_jz,e_jz,add) return add
def cal_fenhong(code): fundinfo = xa.fundinfo(code) total_fenhong = 0 # print(fundinfo.fenhongdate) if (fundinfo.fenhongdate): s = fundinfo.special dates = s[s.date > np.datetime64('2020-01-01 00:00:00')]['date'] # fenhongs = s[s.date > np.datetime64('2020-01-01 00:00:00')]['comment'] # print(tmp.date) for index, date in dates.items(): # print(type(date)) # print(str(date)[:10]) fener = get_fener(date, code) #计算分红日持有份额 fenhong_per_fener = fenhongs[index] #分红日每一份额分红金额 total_fenhong += fenhong_per_fener * fener print('总计分红{}'.format(total_fenhong)) return total_fenhong
def get_fenhong(code): fundinfo = xa.fundinfo(code) # print(fundinfo.fenhongdate) if (fundinfo.fenhongdate): # print(fundinfo.special.loc[]) s = fundinfo.special # print(s.dtypes) # print(s[s['date']]) tmp = s[s.date > np.datetime64('2020-01-01 00:00:00')] # print(tmp) comment = tmp['comment'] fenhong = comment.sum() print('分红总额为{}'.format(fenhong)) for _, value in comment.items(): print(value) return fenhong else: print('分红总额为{}'.format(0)) return 0
def fake_trade_300(fake_code): read = xa.record("./tests/fund_2020.csv", skiprows=1) jjcode_list = list(read.status.columns.values)[1:] #持有的全部基金列表 t_buy, t_get = 0, 0 #总计买入,总计剩余(包括当前剩余及赎回) for code in jjcode_list: trade_info = read.status.loc[:, ['date', code]] # print(trade_info) buy, sell = 0, 0 fe = 0 fundinfo = xa.fundinfo(fake_code) shengoufeilv = fundinfo.rate / 100. for index, row in trade_info.iterrows(): date = row.get('date') dwjz = get_jz(fake_code, date) #假设买的全是hs300 v = row.get(code) if v > 0: buy += v else: sell += v fe += v * (1 - shengoufeilv) / dwjz #份额变动 last_trade_day = datetime.strftime(datetime.now() - timedelta(1), '%Y-%m-%d') dqjz = get_jz(fake_code, last_trade_day) # print(dqjz) dqye = fe * dqjz + sell #包括当前持有金额以及已卖出金额之和 syl = dqye / buy - 1 #收益率 # print('{},{}--份额:{},昨日净值{},当前余额{},总投入{},收益率{},盈利{}'.format(fundinfo.name,last_trade_day,fe,dqjz,dqye,buy,syl,dqye-buy)) print('{},当前余额{},总投入{},收益率{},盈利{}'.format(fake_code, dqye, buy, syl, dqye - buy)) t_buy += buy t_get += dqye print('假设全部买入{},总投入:{},总回报:{},整体收益率:{:.3f},盈利{}\n'.format( fake_code, t_buy, t_get, t_get / t_buy - 1, t_get - t_buy))
def get_fener(deadline_date, code): read = xa.record("./tests/fund_2020.csv", skiprows=1) trade_info = read.status.loc[:, ['date', code]] trade_info = trade_info[trade_info.date < np.datetime64(deadline_date)] # print(trade_info) fundinfo = xa.fundinfo(code) #计算份额变动 fe = 0 for _, row in trade_info.iterrows(): date = row.get('date') dwjz = get_jz(code, date) v = row.get(code) #买入或者卖出金额 if v > 0: # print('申购费率:{}'.format(fundinfo.rate)) fe += v * (1 - fundinfo.rate / 100.) / dwjz else: fe += v / dwjz #这里没有考虑赎回的费率 注意这里不是减法 卖出的话v为负值 print('截止{}持有份额{}'.format(deadline_date, fe)) return fe
import sys sys.path.insert(0, "../") import xalpha as xa import pytest import pandas as pd path = 'demo.csv' path1 = 'demo1.csv' cm = xa.fundinfo('164818') statb = xa.record(path).status statl = xa.record(path1, format="list").status cm_t = xa.trade(cm, statb) ioconf = {'save': True, 'fetch': True, 'path': 'pytest', 'form': 'csv'} def test_trade(): assert cm_t.cftable.loc[2, 'share'] == -129.14 assert round(cm_t.xirrrate('2018-03-03'), 3) == -0.24 assert cm_t.dailyreport('2018-07-29').iloc[0]['单位成本'] == 1.346 cm_t.v_tradecost('2018-08-01') cm_t.v_totvalue('2018-07-31') cm_t.v_tradevolume(freq='M') def test_mul(): with pytest.raises(Exception) as excinfo: cm_m = xa.mulfix(cm_t, totmoney=200) assert str(excinfo.value) == 'You cannot sell first when you never buy' with pytest.raises(Exception) as excinfo: cm_m = xa.mulfix(cm_t, totmoney=300)
import sys sys.path.insert(0, "../") import xalpha as xa from xalpha.exceptions import FundTypeError import pandas as pd import pytest ioconf = {"save": True, "fetch": True, "path": "pytest", "form": "csv"} ca = xa.cashinfo(interest=0.0002, start="2015-01-01") zzhb = xa.indexinfo("0000827", **ioconf) hs300 = xa.fundinfo("000311") zogqb = xa.mfundinfo("001211", **ioconf) def test_fundreport(): # somehow fragile, to be checked r = xa.FundReport("000827") assert r.get_report()[0][:2] == "广发" assert r.analyse_report(1)["bank"][:2] == "兴业" assert r.show_report_list(type_=0)[0]["FUNDCODE"] == "000827" assert r.get_report(id_="AN202003171376532533")[0][:2] == "广发" def test_cash(): assert ( round(ca.price[ca.price["date"] == "2018-01-02"].iloc[0].netvalue, 4) == 1.2453 ) assert ca.code == "mf" date, value, share = ca.shuhui( 300, "2018-01-01", [[pd.Timestamp("2017-01-03"), 200]]
import sys sys.path.insert(0, "../") import xalpha as xa import pytest import pandas as pd path = "demo.csv" path1 = "demo1.csv" cm = xa.fundinfo("164818") statb = xa.record(path).status statl = xa.record(path1, format="list").status cm_t = xa.trade(cm, statb) ioconf = {"save": True, "fetch": True, "path": "pytest", "form": "csv"} def test_trade(): assert cm_t.cftable.loc[2, "share"] == -129.14 assert round(cm_t.xirrrate("2018-03-03"), 3) == -0.24 assert cm_t.dailyreport("2018-07-29").iloc[0]["单位成本"] == 1.346 cm_t.v_tradecost("2018-08-01") cm_t.v_totvalue("2018-07-31") cm_t.v_tradevolume(freq="M") def test_mul(): with pytest.raises(Exception) as excinfo: cm_m = xa.mulfix(cm_t, totmoney=200) assert str(excinfo.value) == "You cannot sell first when you never buy" with pytest.raises(Exception) as excinfo: cm_m = xa.mulfix(cm_t, totmoney=300)
import sys sys.path.insert(0, "../") import xalpha as xa from xalpha.exceptions import FundTypeError import pandas as pd import pytest ioconf = {'save': True, 'fetch': True, 'path': 'pytest', 'form': 'csv'} ca = xa.cashinfo(interest=0.0002, start='2015-01-01') zzhb = xa.indexinfo('0000827', **ioconf) hs300 = xa.fundinfo('000311') zogqb = xa.mfundinfo('001211', **ioconf) def test_cash(): assert round(ca.price[ca.price['date'] == '2018-01-02'].iloc[0].netvalue, 4) == 1.2453 assert ca.code == 'mf' date, value, share = ca.shuhui(300, '2018-01-01', [[pd.Timestamp('2017-01-03'), 200]]) assert date == pd.Timestamp('2018-01-02') assert value == 249.06 assert share == -200 ca.bcmkset(ca) assert ca.alpha() == 0 assert round(ca.total_annualized_returns('2018-01-01'), 4) == 0.0757 def test_index(): assert round(