Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: adding the option to use returns in addition to prices #31

Open
wants to merge 45 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
45 commits
Select commit Hold shift + click to select a range
4270ed4
chore: start implementing return parallel to prices updates and corre…
MetzkerLior May 16, 2024
9b92a3d
chore: change from "for" to "while" in SimpleBacktester run. No use o…
MetzkerLior May 21, 2024
e0d3061
chore: add the ability to load a data source containing returns
MetzkerLior May 28, 2024
a3911c5
chore: add the ability to deal with asset IDs that are integers and n…
MetzkerLior May 28, 2024
a45d2b7
chore: add work_with_prices to SimpleBacktester initialization, setti…
MetzkerLior Jun 3, 2024
53cd4e1
chore: add more variables to be printed in the screen log.
MetzkerLior Jun 3, 2024
a83c426
chore: add last_date_updated to Holding for tracking last price/retur…
MetzkerLior Jun 3, 2024
7f0a5c2
chore: add TODO comment to quants.py
MetzkerLior Jun 3, 2024
20f8a22
chore: add TODO comment to dump.py
MetzkerLior Jun 3, 2024
14f59ff
chore: code review
Caceresenzo Jun 3, 2024
f0a64ac
fix(export/dump): sort by `date` and `ordered`
Caceresenzo Jun 4, 2024
510ccfb
feat(data-source/yahoo): store field in class instead of a default pa…
Caceresenzo Jun 4, 2024
d10dfe3
test: fix some
Caceresenzo Jun 4, 2024
adb32e4
feat(date-iterator): remove iteration feature
Caceresenzo Jun 4, 2024
cf4e663
test(holding): fix
Caceresenzo Jun 4, 2024
7b029c8
test(account): fix
Caceresenzo Jun 4, 2024
0ed02a3
feat(order): include `0` symbol as invalid
Caceresenzo Jun 4, 2024
74c1b1e
fix(order): allow non-zero symbols
Caceresenzo Jun 5, 2024
acbfdf4
fix(account): use `Order.valid` in `Account.close_position`
Caceresenzo Jun 5, 2024
b265246
fix(export/console): add missing spaces
Caceresenzo Jun 5, 2024
91c2c77
fix(data-source/yahoo): call super constructor
Caceresenzo Jun 5, 2024
1bac1f2
test(integration): add
MetzkerLior Jun 6, 2024
bcbb43c
test(integration): backtest
Caceresenzo Jun 6, 2024
a7f8ebe
test: add comparision function
MetzkerLior Jun 7, 2024
a7fe391
test(backtest): assert dataframes
Caceresenzo Jun 7, 2024
89c17c1
test(helper): add column name in assert messages
Caceresenzo Jun 7, 2024
aebd6df
test(helper): adjusting atol
MetzkerLior Jun 7, 2024
8063591
test(helper): add atol as parameter
MetzkerLior Jun 7, 2024
05b86e1
test(backtest): add returns
Caceresenzo Jun 7, 2024
788976b
test(backtest): set returns' paths
Caceresenzo Jun 7, 2024
73734c6
test(helper): adjusting atol for yahoo returns test
MetzkerLior Jun 7, 2024
ca38b00
feat(cli): integrate the parameter work_with_prices in the cli options
xaviergilbert Jun 26, 2024
ce8adf2
chore: change for to enumerate
MetzkerLior Jun 27, 2024
b2c2dc5
Merge branch 'dev' of github.com:crunchdao/backtest into dev
MetzkerLior Jun 27, 2024
3dce27c
feat(value): remove
MetzkerLior Jul 1, 2024
bb491d5
feat: rename equity to nav, add equity_long, and redefine equity
MetzkerLior Jul 1, 2024
f9f67db
refacto!: value to equity
MetzkerLior Jul 1, 2024
a12bdcc
feat: remove debug printings
MetzkerLior Jul 1, 2024
23b195d
chore: merge two options of quantity_in_decimal in one loop
MetzkerLior Jul 1, 2024
2d3312a
fix(tests): remove value from account and holding. rename equity to n…
MetzkerLior Jul 1, 2024
ebf92b1
feat(equity_long): add
MetzkerLior Jul 1, 2024
095628f
fix(FutureWarning): concatenation with empty or all-NA entries is dep…
MetzkerLior Jul 2, 2024
7ec38d6
fix(print)
MetzkerLior Jul 4, 2024
72f3162
remove: writing dump files for debugging
MetzkerLior Jul 4, 2024
dac285c
feat(datasource): add cli flag to specify the type of the data source…
xaviergilbert Jul 8, 2024
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
62 changes: 42 additions & 20 deletions bktest/account.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import datetime
import sys
import typing

Expand All @@ -6,6 +7,8 @@
from .order import CloseResult, Order, OrderResult
from .utils import is_blank

EPSILON = 1e-10


class Account:

Expand All @@ -22,16 +25,25 @@ def __init__(
self.total_short = 0
self._holdings: typing.Dict[str, Holding] = dict()

# TODO: change value to equity
@property
def value(self) -> float:
def equity(self) -> float:
return sum(
holding.market_price
for holding in self._holdings.values()
)

@property
def equity(self) -> float:
return self.cash + self.value
def equity_long(self) -> float:
return sum(
holding.market_price
for holding in self._holdings.values()
if holding.market_price > 0
)

@property
def nav(self) -> float:
return self.cash + self.equity

@property
def symbols(self) -> typing.Set[str]:
Expand All @@ -44,75 +56,85 @@ def holdings(self) -> typing.List[Holding]:
def find_holding(self, symbol: str):
return self._holdings.get(symbol, None)

def place_order(self, order: Order) -> OrderResult:
def place_order(self, order: Order, date: datetime.date) -> OrderResult:
result = OrderResult(order=order)
if not order.valid:
return result

result.success = True

if order.quantity == 0:
return result

result.fee = self.fee_model.get_order_fee(order)

self._handle_cash(order, result.fee)

# Handle holdings in the account.
holding = self.find_holding(order.symbol)

if holding:
assert holding.last_date_updated == date, "holding price is not up-to-date"
holding.merge(order)

if not holding.quantity:
del self._holdings[order.symbol]
else:
self._holdings[order.symbol] = Holding.from_order(order)

self._holdings[order.symbol] = Holding(
order.symbol,
order.quantity,
order.price,
date = date
)

if abs(self._holdings[order.symbol].quantity) < EPSILON: # if quantity is zero
del self._holdings[order.symbol]

return result

def order_position(self, order: Order) -> OrderResult:
relative = self.to_relative_order(order)
def order_position(self, order: Order, date) -> OrderResult:
relative = self.to_relative_order(order, date)

return self.place_order(relative)
return self.place_order(relative, date)

def close_position(self, symbol: str, price: float = None) -> CloseResult:
order = Order(symbol, 0, price)
result = CloseResult(order=order)

if is_blank(order.symbol):
if not order.valid:
# TODO: Should be an ERROR?
return result

result.success = True

holding = self.find_holding(order.symbol)

if holding:
order.quantity = -holding.quantity

# If the symbol is not traded on date the price is None.
if order.price is None:
order.price = holding.price
print(f"[warning] no price available for {order.symbol}, using last price: {order.price}", file=sys.stderr)
print(f"[warning] in close_position no price available for {order.symbol}, using last price: {order.price}", file=sys.stderr)

result.fee = self.fee_model.get_order_fee(order)

self._handle_cash(order, result.fee)

del self._holdings[order.symbol]

result.success = True
else:
# TODO: Should be an ERROR?
result.missing = True

return result

def to_relative_order(self, order: Order):
def to_relative_order(self, order: Order, date: datetime.date):
holding = self.find_holding(order.symbol)

if not holding or order.quantity is None:
return order

assert holding.last_date_updated == date

return Order(
order.symbol,
order.quantity - holding.quantity,
order.price
order.price,
)

def _handle_cash(self, order: Order, fee: float):
Expand Down
Loading
Loading