Skip to content

Commit 613b1aa

Browse files
committed
remove nose and mock dependencies, replace nose approx with pytest approx, autoformat bench
1 parent fecdfc3 commit 613b1aa

File tree

7 files changed

+103
-98
lines changed

7 files changed

+103
-98
lines changed

bt/algos.py

+5-6
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@
1010
import numpy as np
1111
import pandas as pd
1212
import sklearn.covariance
13-
from future.utils import iteritems
1413

1514
import bt
1615
from bt.core import Algo, AlgoStack, SecurityBase, is_zero
@@ -1060,7 +1059,7 @@ def __init__(self, scale):
10601059

10611060
def __call__(self, target):
10621061
target.temp["weights"] = {
1063-
k: self.scale * w for k, w in iteritems(target.temp["weights"])
1062+
k: self.scale * w for k, w in target.temp["weights"].items()
10641063
}
10651064
return True
10661065

@@ -1809,7 +1808,7 @@ def __call__(self, target):
18091808
base = base * (1 - target.temp["cash"])
18101809

18111810
# Turn off updating while we rebalance each child
1812-
for item in iteritems(targets):
1811+
for item in targets.items():
18131812
target.rebalance(item[1], child=item[0], base=base, update=False)
18141813

18151814
# Now update
@@ -2054,7 +2053,7 @@ def __call__(self, target):
20542053
# Find securities that are candidate for closing
20552054
sec_names = [
20562055
sec_name
2057-
for sec_name, sec in iteritems(target.children)
2056+
for sec_name, sec in target.children.items()
20582057
if isinstance(sec, SecurityBase)
20592058
and sec_name in close_dates.index
20602059
and sec_name not in target.perm["closed"]
@@ -2108,7 +2107,7 @@ def __call__(self, target):
21082107
# Find securities that are candidate for roll
21092108
sec_names = [
21102109
sec_name
2111-
for sec_name, sec in iteritems(target.children)
2110+
for sec_name, sec in target.children.items()
21122111
if isinstance(sec, SecurityBase)
21132112
and sec_name in roll_data.index
21142113
and sec_name not in target.perm["rolled"]
@@ -2127,7 +2126,7 @@ def __call__(self, target):
21272126
target.close(sec_name, update=False)
21282127

21292128
# Do all the new transactions at the end, to do any necessary aggregations first
2130-
for new_sec, quantity in iteritems(transactions):
2129+
for new_sec, quantity in transactions.items():
21312130
target.transact(quantity, new_sec, update=False)
21322131

21332132
# Now update

bt/core.py

+1-2
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@
99
import cython as cy
1010
import numpy as np
1111
import pandas as pd
12-
from future.utils import iteritems
1312

1413

1514
PAR = 100.0
@@ -147,7 +146,7 @@ def _add_children(self, children, dc):
147146
if isinstance(children, dict):
148147
# Preserve the names from the dictionary by renaming the nodes
149148
tmp = []
150-
for name, c in iteritems(children):
149+
for name, c in children.items():
151150
if isinstance(c, str):
152151
tmp.append(name)
153152
else:

setup.py

-2
Original file line numberDiff line numberDiff line change
@@ -48,9 +48,7 @@ def local_file(filename):
4848
"ffn>=0.3.5",
4949
"flake8",
5050
"flake8-black",
51-
"future",
5251
"matplotlib>=2",
53-
"mock",
5452
"numpy>=1",
5553
"pandas>=0.19",
5654
"pyprind>=2.11",

tests/bench.py

+53-39
Original file line numberDiff line numberDiff line change
@@ -9,65 +9,79 @@
99

1010
def benchmark_1():
1111
x = np.random.randn(10000, 1000) * 0.01
12-
idx = pd.date_range('1990-01-01', freq='B', periods=x.shape[0])
12+
idx = pd.date_range("1990-01-01", freq="B", periods=x.shape[0])
1313
data = np.exp(pd.DataFrame(x, index=idx).cumsum())
1414

15-
s = bt.Strategy('s', [bt.algos.RunMonthly(),
16-
bt.algos.SelectRandomly(len(data.columns) / 2),
17-
bt.algos.WeighRandomly(),
18-
bt.algos.Rebalance()])
15+
s = bt.Strategy(
16+
"s",
17+
[
18+
bt.algos.RunMonthly(),
19+
bt.algos.SelectRandomly(len(data.columns) / 2),
20+
bt.algos.WeighRandomly(),
21+
bt.algos.Rebalance(),
22+
],
23+
)
1924

2025
t = bt.Backtest(s, data)
2126
return bt.run(t)
22-
27+
28+
2329
def benchmark_2():
2430
x = np.random.randn(10000, 1000) * 0.01
25-
idx = pd.date_range('1990-01-01', freq='B', periods=x.shape[0])
31+
idx = pd.date_range("1990-01-01", freq="B", periods=x.shape[0])
2632
data = np.exp(pd.DataFrame(x, index=idx).cumsum())
2733
bidoffer = data * 0.01
28-
coupons = data * 0.
29-
s = bt.FixedIncomeStrategy('s',
30-
algos = [bt.algos.RunMonthly(),
31-
bt.algos.SelectRandomly(len(data.columns) / 2),
32-
bt.algos.WeighRandomly(),
33-
bt.algos.Rebalance()],
34-
children = [ bt.CouponPayingSecurity(c)
35-
for c in data ]
36-
)
34+
coupons = data * 0.0
35+
s = bt.FixedIncomeStrategy(
36+
"s",
37+
algos=[
38+
bt.algos.RunMonthly(),
39+
bt.algos.SelectRandomly(len(data.columns) / 2),
40+
bt.algos.WeighRandomly(),
41+
bt.algos.Rebalance(),
42+
],
43+
children=[bt.CouponPayingSecurity(c) for c in data],
44+
)
3745

38-
t = bt.Backtest(s, data, additional_data = {'bidoffer':bidoffer,
39-
'coupons':coupons})
46+
t = bt.Backtest(s, data, additional_data={"bidoffer": bidoffer, "coupons": coupons})
4047
return bt.run(t)
4148

49+
4250
def benchmark_3():
4351
# Similar to benchmark_1, but with trading in only a small subset of assets
4452
# However, because the "multipier" is used, we can't just pass the string
4553
# names to the constructor, and so the solution is to use the lazy_add flag.
4654
# Changing lazy_add to False demonstrates the performance gain.
4755
# i.e. on Win32, it went from 4.3s with the flag to 10.9s without.
48-
56+
4957
x = np.random.randn(10000, 1000) * 0.01
50-
idx = pd.date_range('1990-01-01', freq='B', periods=x.shape[0])
58+
idx = pd.date_range("1990-01-01", freq="B", periods=x.shape[0])
5159
data = np.exp(pd.DataFrame(x, index=idx).cumsum())
52-
children = [ bt.Security(name=i, multiplier=10, lazy_add=False)
53-
for i in range(1000) ]
54-
s = bt.Strategy('s', [bt.algos.RunMonthly(),
55-
bt.algos.SelectThese([0,1]),
56-
bt.algos.WeighRandomly(),
57-
bt.algos.Rebalance()], children = children)
60+
children = [bt.Security(name=i, multiplier=10, lazy_add=False) for i in range(1000)]
61+
s = bt.Strategy(
62+
"s",
63+
[
64+
bt.algos.RunMonthly(),
65+
bt.algos.SelectThese([0, 1]),
66+
bt.algos.WeighRandomly(),
67+
bt.algos.Rebalance(),
68+
],
69+
children=children,
70+
)
5871

5972
t = bt.Backtest(s, data)
6073
return bt.run(t)
61-
62-
if __name__ == '__main__':
63-
print('\n\n\n================= Benchmark 1 =======================\n')
64-
cProfile.run('benchmark_1()', sort='tottime')
65-
print('\n----------------- Benchmark 1 -----------------------\n\n\n')
66-
67-
print('\n\n\n================= Benchmark 2 =======================\n')
68-
cProfile.run('benchmark_2()', sort='tottime')
69-
print('\n----------------- Benchmark 2 -----------------------\n\n\n')
70-
71-
print('\n\n\n================= Benchmark 3 =======================\n')
72-
cProfile.run('benchmark_3()', sort='cumtime')
73-
print('\n----------------- Benchmark 3 -----------------------\n\n\n')
74+
75+
76+
if __name__ == "__main__":
77+
print("\n\n\n================= Benchmark 1 =======================\n")
78+
cProfile.run("benchmark_1()", sort="tottime")
79+
print("\n----------------- Benchmark 1 -----------------------\n\n\n")
80+
81+
print("\n\n\n================= Benchmark 2 =======================\n")
82+
cProfile.run("benchmark_2()", sort="tottime")
83+
print("\n----------------- Benchmark 2 -----------------------\n\n\n")
84+
85+
print("\n\n\n================= Benchmark 3 =======================\n")
86+
cProfile.run("benchmark_3()", sort="cumtime")
87+
print("\n----------------- Benchmark 3 -----------------------\n\n\n")

tests/test_algos.py

+8-14
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,11 @@
11
from __future__ import division
22
from datetime import datetime
3+
from unittest import mock
34

4-
import sys
5-
if sys.version_info < (3, 3):
6-
import mock
7-
else:
8-
from unittest import mock
9-
10-
11-
import pandas as pd
125
import numpy as np
6+
import pandas as pd
7+
import pytest
138
import random
14-
from nose.tools import assert_almost_equal as aae
159

1610
import bt
1711
import bt.algos as algos
@@ -1284,8 +1278,8 @@ def test_weigh_inv_vol():
12841278
weights = s.temp['weights']
12851279
assert len(weights) == 2
12861280
assert weights['c2'] > weights['c1']
1287-
aae(weights['c1'], 0.020, 3)
1288-
aae(weights['c2'], 0.980, 3)
1281+
assert weights['c1'] == pytest.approx(0.020, 3)
1282+
assert weights['c2'] == pytest.approx(0.980, 3)
12891283

12901284

12911285
@mock.patch('ffn.calc_mean_var_weights')
@@ -1330,7 +1324,7 @@ def test_weigh_randomly():
13301324
assert algo(s)
13311325
weights = s.temp['weights']
13321326
assert len( weights ) == 3
1333-
aae( sum( weights.values() ), 0.95 )
1327+
assert sum( weights.values()) == pytest.approx(0.95)
13341328
for c in s.temp['selected']:
13351329
assert weights[c] <= 0.5
13361330
assert weights[c] >= 0.3
@@ -2187,11 +2181,11 @@ def test_hedge_risk():
21872181

21882182
# Check that risk is hedged!
21892183
assert s.risk['Risk1'] == 0
2190-
aae( s.risk['Risk2'], 0, 13)
2184+
assert s.risk['Risk2'] == pytest.approx(0, 13)
21912185
# Check that positions are nonzero (trivial solution)
21922186
assert c1.position == 100
21932187
assert c2.position == -10
2194-
aae( c3.position, -(100*2 - 10*5)/10., 13)
2188+
assert c3.position == pytest.approx(-(100*2 - 10*5)/10., 13)
21952189

21962190

21972191
def test_hedge_risk_nan():

tests/test_backtest.py

+8-9
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,13 @@
11
from __future__ import division
2-
import bt
3-
import pandas as pd
2+
43
import numpy as np
5-
from nose.tools import assert_almost_equal as aae
4+
import pandas as pd
5+
import pytest
66
import random
7-
import sys
8-
if sys.version_info < (3, 3):
9-
import mock
10-
else:
11-
from unittest import mock
7+
8+
from unittest import mock
9+
10+
import bt
1211

1312

1413
def test_backtest_copies_strategy():
@@ -325,7 +324,7 @@ def test_RenomalizedFixedIncomeResult():
325324

326325
# Renormalizing results to a constant size "fixes" this
327326
norm_res = bt.backtest.RenormalizedFixedIncomeResult( 1e6, *res.backtest_list )
328-
aae( norm_res.stats['s'].total_return, t.strategy.value / 1e6, 16 )
327+
assert norm_res.stats['s'].total_return == pytest.approx(t.strategy.value / 1e6, 16)
329328

330329
# Check that using the lagged notional value series leads to the same results
331330
# as the original calculation. This proves that we can re-derive the price

0 commit comments

Comments
 (0)