Skip to content

Commit

Permalink
fix bug in trade
Browse files Browse the repository at this point in the history
  • Loading branch information
refraction-ray committed May 13, 2020
1 parent 1e1985f commit df5afc4
Show file tree
Hide file tree
Showing 4 changed files with 39 additions and 6 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
### fixed
* xirrrate 支持调整时间起点,并修改内部 bug
* 允许账单的 date 不出现在第一列
* 修复了 trade 不支持按周计价净值基金的 bug

## v0.8.10 - 2020.05.01
### added
Expand Down
9 changes: 9 additions & 0 deletions tests/test_trade.py
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,15 @@ def test_policy_buyandhold():
assert round(cm_t2.xirrrate("2019-08-12", guess=-0.9), 2) == -0.33


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_policy_scheduled():
auto = xa.policy.scheduled(
cm, 1000, pd.date_range("2015-07-01", "2018-07-01", freq="W-THU")
Expand Down
33 changes: 28 additions & 5 deletions xalpha/trade.py
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,7 @@ def __init__(self, infoobj, status):
self.cftable = pd.DataFrame([], columns=["date", "cash", "share"])
self.remtable = pd.DataFrame([], columns=["date", "rem"])
self.status = status.loc[:, ["date", code]]
self.status = self.status[self.status[code] != 0]
self._arrange()

def _arrange(self):
Expand All @@ -221,7 +222,9 @@ def _addrow(self):
分级份额折算日封闭无法买入,所以程序直接忽略当天的买卖。因此不会出现多个操作共存的情形。
"""
# the design on data remtable is disaster, it is very dangerous though works now

# possibly failing cases include:
# 买卖日记录是节假日,而顺延的日期恰好是折算日(理论上无法申赎)或分红日(可能由于 date 和 rdate 的错位而没有考虑到),
# 又比如周日申购记录,周一申购记录,那么周日记录会现金流记在周一,继续现金流标更新将从周二开始,周一数据被丢弃
code = self.aim.code
if len(self.cftable) == 0:
if len(self.status[self.status[code] != 0]) == 0:
Expand All @@ -238,7 +241,10 @@ def _addrow(self):
raise TradeBehaviorError("You cannot sell first when you never buy")
elif len(self.cftable) > 0:
recorddate = list(self.status.date)
lastdate = self.cftable.iloc[-1].date + pd.Timedelta(1, unit="d")
if not getattr(self, "lastdate", None):
lastdate = self.cftable.iloc[-1].date + pd.Timedelta(1, unit="d")
else:
lastdate = self.lastdate + pd.Timedelta(1, unit="d")
while (lastdate not in self.aim.specialdate) and (
(lastdate not in recorddate)
or (
Expand All @@ -255,14 +261,29 @@ def _addrow(self):
if (lastdate - yesterdayobj()).days >= 1:
raise Exception("no other info to be add into cashflow table")
date = lastdate
# 无净值日优先后移,无法后移则前移
if len(self.price[self.price["date"] >= date]) > 0:
date = self.price[self.price["date"] >= date].iloc[0]["date"]
else:
date = self.price[self.price["date"] <= date].iloc[-1]["date"]
if date != lastdate and date in list(self.status.date):
# 日期平移到了其他记录日,很可能出现问题!
logger.warning(
"账单日期 %s 非 %s 的净值记录日期,日期智能平移后 %s 与账单其他日期重合!交易处理极可能出现问题!! "
"靠后日期的记录被覆盖" % (lastdate, self.code, date)
)
self.lastdate = lastdate
if date > lastdate:
self.lastdate = date
# see https://github.com/refraction-ray/xalpha/issues/27, begin new date from last one in df is not reliable
label = self.aim.dividend_label # 现金分红 0, 红利再投 1
cash = 0
share = 0
rem = self.remtable.iloc[-1].rem
rdate = date
if (date in recorddate) and (date not in self.aim.zhesuandate):
if (lastdate in recorddate) and (date not in self.aim.zhesuandate):
# deal with buy and sell and label the fenhongzaitouru, namely one label a 0.05 in the original table to label fenhongzaitouru
value = self.status[self.status["date"] == date].iloc[0].loc[code]
value = self.status[self.status["date"] <= lastdate].iloc[-1].loc[code]
fenhongmark = round(10 * value - int(10 * value), 1)
if fenhongmark == 0.5 and label == 0:
label = 1 # fenhong reinvest
Expand All @@ -282,7 +303,9 @@ def _addrow(self):
_, rem = rm.sell(rem, -dshare, rdate)
elif value >= -0.005 and value < 0:
# value now stands for the ratio to be sold in terms of remain positions, -0.005 stand for sell 100%
remainshare = sum(self.cftable.loc[:, "share"])
remainshare = sum(
self.cftable[self.cftable["date"] <= date].loc[:, "share"]
)
ratio = -value / 0.005
rdate, dcash, dshare = self.aim.shuhui(
remainshare * ratio, date, self.remtable.iloc[-1].rem
Expand Down
2 changes: 1 addition & 1 deletion xalpha/universal.py
Original file line number Diff line number Diff line change
Expand Up @@ -847,7 +847,7 @@ def _get_daily(
3. 对于美国市场的股票,指数,ETF 等,直接使用其字母缩写代码即可。
4. 对于人民币中间价数据,使用 "USD/CNY" 的形式,具体可能的值可在 http://www.chinamoney.com.cn/chinese/bkccpr/ 历史数据的横栏查询
4. 对于人民币中间价数据,使用 "USD/CNY" 的形式,具体可能的值可在 http://www.chinamoney.com.cn/chinese/bkccpr/ 历史数据的横栏查询,注意日元需要用 100JPY/CNY.
5. 对于所有可以在 cn.investing.com 网站查到的金融产品,其代码可以是该网站对应的统一代码,或者是网址部分,比如 DAX 30 的概览页面为 https://cn.investing.com/indices/germany-30,那么对应代码即为 "indices/germany-30"。也可去网页 inspect 手动查找其内部代码(一般不需要自己做,推荐直接使用网页url作为 code 变量值),手动 inspect 加粗的实时价格,其对应的网页 span class 中的 pid 的数值即为内部代码。
Expand Down

0 comments on commit df5afc4

Please sign in to comment.