Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
polakowo
GitHub Repository: polakowo/vectorbt
Path: blob/master/tests/test_portfolio.py
1071 views
1
from copy import deepcopy
2
from datetime import datetime, timedelta
3
4
import numpy as np
5
import pandas as pd
6
import pytest
7
from numba import njit, typeof
8
from numba.typed import List
9
10
import vectorbt as vbt
11
from tests.utils import record_arrays_close
12
from vectorbt.generic.enums import drawdown_dt
13
from vectorbt.portfolio import nb
14
from vectorbt.portfolio.enums import *
15
from vectorbt.utils.random_ import set_seed
16
17
seed = 42
18
19
day_dt = np.timedelta64(86400000000000)
20
21
price = pd.Series([1., 2., 3., 4., 5.], index=pd.Index([
22
datetime(2020, 1, 1),
23
datetime(2020, 1, 2),
24
datetime(2020, 1, 3),
25
datetime(2020, 1, 4),
26
datetime(2020, 1, 5)
27
]))
28
price_wide = price.vbt.tile(3, keys=['a', 'b', 'c'])
29
big_price = pd.DataFrame(np.random.uniform(size=(1000,)))
30
big_price.index = [datetime(2018, 1, 1) + timedelta(days=i) for i in range(1000)]
31
big_price_wide = big_price.vbt.tile(1000)
32
33
34
# ############# Global ############# #
35
36
def setup_module():
37
vbt.settings.numba['check_func_suffix'] = True
38
vbt.settings.portfolio['attach_call_seq'] = True
39
vbt.settings.caching.enabled = False
40
vbt.settings.caching.whitelist = []
41
vbt.settings.caching.blacklist = []
42
43
44
def teardown_module():
45
vbt.settings.reset()
46
47
48
# ############# nb ############# #
49
50
def assert_same_tuple(tup1, tup2):
51
for i in range(len(tup1)):
52
assert tup1[i] == tup2[i] or np.isnan(tup1[i]) and np.isnan(tup2[i])
53
54
55
def test_execute_order_nb():
56
# Errors, ignored and rejected orders
57
with pytest.raises(Exception):
58
_ = nb.execute_order_nb(
59
ProcessOrderState(-100., 100., 0., 100., 10., 1100., 0, 0),
60
nb.order_nb(10, 10))
61
with pytest.raises(Exception):
62
_ = nb.execute_order_nb(
63
ProcessOrderState(np.nan, 100., 0., 100., 10., 1100., 0, 0),
64
nb.order_nb(10, 10))
65
with pytest.raises(Exception):
66
_ = nb.execute_order_nb(
67
ProcessOrderState(100., np.inf, 0., 100., 10., 1100., 0, 0),
68
nb.order_nb(10, 10))
69
with pytest.raises(Exception):
70
_ = nb.execute_order_nb(
71
ProcessOrderState(100., np.nan, 0., 100., 10., 1100., 0, 0),
72
nb.order_nb(10, 10))
73
with pytest.raises(Exception):
74
_ = nb.execute_order_nb(
75
ProcessOrderState(100., 100., np.nan, 100., 10., 1100., 0, 0),
76
nb.order_nb(10, 10))
77
with pytest.raises(Exception):
78
_ = nb.execute_order_nb(
79
ProcessOrderState(100., 100., -10., 100., 10., 1100., 0, 0),
80
nb.order_nb(10, 10))
81
with pytest.raises(Exception):
82
_ = nb.execute_order_nb(
83
ProcessOrderState(100., 100., 0., np.nan, 10., 1100., 0, 0),
84
nb.order_nb(10, 10))
85
with pytest.raises(Exception):
86
_ = nb.execute_order_nb(
87
ProcessOrderState(100., 100., 0., 100., 10., 1100., 0, 0),
88
nb.order_nb(10, 10, size_type=-2))
89
with pytest.raises(Exception):
90
_ = nb.execute_order_nb(
91
ProcessOrderState(100., 100., 0., 100., 10., 1100., 0, 0),
92
nb.order_nb(10, 10, size_type=20))
93
with pytest.raises(Exception):
94
_ = nb.execute_order_nb(
95
ProcessOrderState(100., 100., 0., 100., 10., 1100., 0, 0),
96
nb.order_nb(10, 10, direction=-2))
97
with pytest.raises(Exception):
98
_ = nb.execute_order_nb(
99
ProcessOrderState(100., 100., 0., 100., 10., 1100., 0, 0),
100
nb.order_nb(10, 10, direction=20))
101
with pytest.raises(Exception):
102
_ = nb.execute_order_nb(
103
ProcessOrderState(100., -100., 0., 100., 10., 1100., 0, 0),
104
nb.order_nb(10, 10, direction=Direction.LongOnly))
105
with pytest.raises(Exception):
106
_ = nb.execute_order_nb(
107
ProcessOrderState(100., 100., 0., 100., 10., 1100., 0, 0),
108
nb.order_nb(10, 10, direction=Direction.ShortOnly))
109
with pytest.raises(Exception):
110
_ = nb.execute_order_nb(
111
ProcessOrderState(100., 100., 0., 100., 10., 1100., 0, 0),
112
nb.order_nb(10, np.inf))
113
with pytest.raises(Exception):
114
_ = nb.execute_order_nb(
115
ProcessOrderState(100., 100., 0., 100., 10., 1100., 0, 0),
116
nb.order_nb(10, -10))
117
with pytest.raises(Exception):
118
_ = nb.execute_order_nb(
119
ProcessOrderState(100., 100., 0., 100., 10., 1100., 0, 0),
120
nb.order_nb(10, 10, fees=np.inf))
121
with pytest.raises(Exception):
122
_ = nb.execute_order_nb(
123
ProcessOrderState(100., 100., 0., 100., 10., 1100., 0, 0),
124
nb.order_nb(10, 10, fees=np.nan))
125
with pytest.raises(Exception):
126
_ = nb.execute_order_nb(
127
ProcessOrderState(100., 100., 0., 100., 10., 1100., 0, 0),
128
nb.order_nb(10, 10, fixed_fees=np.inf))
129
with pytest.raises(Exception):
130
_ = nb.execute_order_nb(
131
ProcessOrderState(100., 100., 0., 100., 10., 1100., 0, 0),
132
nb.order_nb(10, 10, fixed_fees=np.nan))
133
with pytest.raises(Exception):
134
_ = nb.execute_order_nb(
135
ProcessOrderState(100., 100., 0., 100., 10., 1100., 0, 0),
136
nb.order_nb(10, 10, slippage=np.inf))
137
with pytest.raises(Exception):
138
_ = nb.execute_order_nb(
139
ProcessOrderState(100., 100., 0., 100., 10., 1100., 0, 0),
140
nb.order_nb(10, 10, slippage=-1))
141
with pytest.raises(Exception):
142
_ = nb.execute_order_nb(
143
ProcessOrderState(100., 100., 0., 100., 10., 1100., 0, 0),
144
nb.order_nb(10, 10, min_size=np.inf))
145
with pytest.raises(Exception):
146
_ = nb.execute_order_nb(
147
ProcessOrderState(100., 100., 0., 100., 10., 1100., 0, 0),
148
nb.order_nb(10, 10, min_size=-1))
149
with pytest.raises(Exception):
150
_ = nb.execute_order_nb(
151
ProcessOrderState(100., 100., 0., 100., 10., 1100., 0, 0),
152
nb.order_nb(10, 10, max_size=0))
153
with pytest.raises(Exception):
154
_ = nb.execute_order_nb(
155
ProcessOrderState(100., 100., 0., 100., 10., 1100., 0, 0),
156
nb.order_nb(10, 10, max_size=-10))
157
with pytest.raises(Exception):
158
_ = nb.execute_order_nb(
159
ProcessOrderState(100., 100., 0., 100., 10., 1100., 0, 0),
160
nb.order_nb(10, 10, reject_prob=np.nan))
161
with pytest.raises(Exception):
162
_ = nb.execute_order_nb(
163
ProcessOrderState(100., 100., 0., 100., 10., 1100., 0, 0),
164
nb.order_nb(10, 10, reject_prob=-1))
165
with pytest.raises(Exception):
166
_ = nb.execute_order_nb(
167
ProcessOrderState(100., 100., 0., 100., 10., 1100., 0, 0),
168
nb.order_nb(10, 10, reject_prob=2))
169
with pytest.raises(Exception):
170
_ = nb.execute_order_nb(
171
ProcessOrderState(100., 100., 0., 100., 10., 1100.),
172
nb.order_nb(10, 10, size_granularity=-10))
173
174
exec_state, order_result = nb.execute_order_nb(
175
ProcessOrderState(100., 100., 0., 100., 10., np.nan, 0, 0),
176
nb.order_nb(1, 10, size_type=SizeType.TargetPercent))
177
assert exec_state == ExecuteOrderState(cash=100.0, position=100.0, debt=0.0, free_cash=100.0)
178
assert_same_tuple(order_result, OrderResult(
179
size=np.nan, price=np.nan, fees=np.nan, side=-1, status=1, status_info=3))
180
exec_state, order_result = nb.execute_order_nb(
181
ProcessOrderState(100., 100., 0., 100., 10., -10., 0, 0),
182
nb.order_nb(1, 10, size_type=SizeType.TargetPercent))
183
assert exec_state == ExecuteOrderState(cash=100.0, position=100.0, debt=0.0, free_cash=100.0)
184
assert_same_tuple(order_result, OrderResult(
185
size=np.nan, price=np.nan, fees=np.nan, side=-1, status=2, status_info=4))
186
with pytest.raises(Exception):
187
_ = nb.execute_order_nb(
188
ProcessOrderState(100., 100., 0., 100., np.inf, 1100., 0, 0),
189
nb.order_nb(10, 10, size_type=SizeType.Value))
190
with pytest.raises(Exception):
191
_ = nb.execute_order_nb(
192
ProcessOrderState(100., 100., 0., 100., -10., 1100, 0, 0),
193
nb.order_nb(10, 10, size_type=SizeType.Value))
194
exec_state, order_result = nb.execute_order_nb(
195
ProcessOrderState(100., 100., 0., 100., np.nan, 1100., 0, 0),
196
nb.order_nb(10, 10, size_type=SizeType.Value))
197
assert exec_state == ExecuteOrderState(cash=100.0, position=100.0, debt=0.0, free_cash=100.0)
198
with pytest.raises(Exception):
199
_ = nb.execute_order_nb(
200
ProcessOrderState(100., 100., 0., 100., np.inf, 1100., 0, 0),
201
nb.order_nb(10, 10, size_type=SizeType.TargetValue))
202
with pytest.raises(Exception):
203
_ = nb.execute_order_nb(
204
ProcessOrderState(100., 100., 0., 100., -10., 1100, 0, 0),
205
nb.order_nb(10, 10, size_type=SizeType.TargetValue))
206
exec_state, order_result = nb.execute_order_nb(
207
ProcessOrderState(100., 100., 0., 100., np.nan, 1100., 0, 0),
208
nb.order_nb(10, 10, size_type=SizeType.TargetValue))
209
assert exec_state == ExecuteOrderState(cash=100.0, position=100.0, debt=0.0, free_cash=100.0)
210
assert_same_tuple(order_result, OrderResult(
211
size=np.nan, price=np.nan, fees=np.nan, side=-1, status=1, status_info=2))
212
exec_state, order_result = nb.execute_order_nb(
213
ProcessOrderState(100., -10., 0., 100., 10., 1100., 0, 0),
214
nb.order_nb(np.inf, 10, direction=Direction.ShortOnly))
215
assert exec_state == ExecuteOrderState(cash=200.0, position=-20.0, debt=100.0, free_cash=0.0)
216
assert_same_tuple(order_result, OrderResult(
217
size=10.0, price=10.0, fees=0.0, side=1, status=0, status_info=-1))
218
exec_state, order_result = nb.execute_order_nb(
219
ProcessOrderState(100., -10., 0., 100., 10., 1100., 0, 0),
220
nb.order_nb(-np.inf, 10, direction=Direction.Both))
221
assert exec_state == ExecuteOrderState(cash=200.0, position=-20.0, debt=100.0, free_cash=0.0)
222
assert_same_tuple(order_result, OrderResult(
223
size=10.0, price=10.0, fees=0.0, side=1, status=0, status_info=-1))
224
exec_state, order_result = nb.execute_order_nb(
225
ProcessOrderState(100., 10., 0., 100., 10., 1100., 0, 0),
226
nb.order_nb(0, 10))
227
assert exec_state == ExecuteOrderState(cash=100.0, position=10.0, debt=0.0, free_cash=100.0)
228
assert_same_tuple(order_result, OrderResult(
229
size=np.nan, price=np.nan, fees=np.nan, side=-1, status=1, status_info=5))
230
exec_state, order_result = nb.execute_order_nb(
231
ProcessOrderState(100., 100., 0., 100., 10., 1100., 0, 0),
232
nb.order_nb(15, 10, max_size=10, allow_partial=False))
233
assert exec_state == ExecuteOrderState(cash=100.0, position=100.0, debt=0.0, free_cash=100.0)
234
assert_same_tuple(order_result, OrderResult(
235
size=np.nan, price=np.nan, fees=np.nan, side=-1, status=2, status_info=9))
236
exec_state, order_result = nb.execute_order_nb(
237
ProcessOrderState(100., 100., 0., 100., 10., 1100., 0, 0),
238
nb.order_nb(10, 10, reject_prob=1.))
239
assert exec_state == ExecuteOrderState(cash=100.0, position=100.0, debt=0.0, free_cash=100.0)
240
assert_same_tuple(order_result, OrderResult(
241
size=np.nan, price=np.nan, fees=np.nan, side=-1, status=2, status_info=10))
242
exec_state, order_result = nb.execute_order_nb(
243
ProcessOrderState(0., 100., 0., 0., 10., 1100., 0, 0),
244
nb.order_nb(10, 10, direction=Direction.LongOnly))
245
assert exec_state == ExecuteOrderState(cash=0.0, position=100.0, debt=0.0, free_cash=0.0)
246
assert_same_tuple(order_result, OrderResult(
247
size=np.nan, price=np.nan, fees=np.nan, side=-1, status=2, status_info=7))
248
exec_state, order_result = nb.execute_order_nb(
249
ProcessOrderState(0., 100., 0., 0., 10., 1100., 0, 0),
250
nb.order_nb(10, 10, direction=Direction.Both))
251
assert exec_state == ExecuteOrderState(cash=0.0, position=100.0, debt=0.0, free_cash=0.0)
252
assert_same_tuple(order_result, OrderResult(
253
size=np.nan, price=np.nan, fees=np.nan, side=-1, status=2, status_info=7))
254
with pytest.raises(Exception):
255
_ = nb.execute_order_nb(
256
ProcessOrderState(np.inf, 100, 0., np.inf, np.nan, 1100., 0, 0),
257
nb.order_nb(np.inf, 10, direction=Direction.LongOnly))
258
with pytest.raises(Exception):
259
_ = nb.execute_order_nb(
260
ProcessOrderState(np.inf, 100., 0., np.inf, 10., 1100., 0, 0),
261
nb.order_nb(np.inf, 10, direction=Direction.Both))
262
exec_state, order_result = nb.execute_order_nb(
263
ProcessOrderState(100., 0., 0., 100., 10., 1100., 0, 0),
264
nb.order_nb(-10, 10, direction=Direction.ShortOnly))
265
assert exec_state == ExecuteOrderState(cash=100.0, position=0.0, debt=0.0, free_cash=100.0)
266
assert_same_tuple(order_result, OrderResult(
267
size=np.nan, price=np.nan, fees=np.nan, side=-1, status=2, status_info=8))
268
with pytest.raises(Exception):
269
_ = nb.execute_order_nb(
270
ProcessOrderState(np.inf, 100., 0., np.inf, 10., 1100., 0, 0),
271
nb.order_nb(-np.inf, 10, direction=Direction.ShortOnly))
272
with pytest.raises(Exception):
273
_ = nb.execute_order_nb(
274
ProcessOrderState(np.inf, 100., 0., np.inf, 10., 1100., 0, 0),
275
nb.order_nb(-np.inf, 10, direction=Direction.Both))
276
exec_state, order_result = nb.execute_order_nb(
277
ProcessOrderState(100., 0., 0., 100., 10., 1100., 0, 0),
278
nb.order_nb(-10, 10, direction=Direction.LongOnly))
279
assert exec_state == ExecuteOrderState(cash=100.0, position=0.0, debt=0.0, free_cash=100.0)
280
assert_same_tuple(order_result, OrderResult(
281
size=np.nan, price=np.nan, fees=np.nan, side=-1, status=2, status_info=8))
282
exec_state, order_result = nb.execute_order_nb(
283
ProcessOrderState(100., 100., 0., 100., 10., 1100., 0, 0),
284
nb.order_nb(10, 10, fixed_fees=100))
285
assert exec_state == ExecuteOrderState(cash=100.0, position=100.0, debt=0.0, free_cash=100.0)
286
assert_same_tuple(order_result, OrderResult(
287
size=np.nan, price=np.nan, fees=np.nan, side=-1, status=2, status_info=11))
288
exec_state, order_result = nb.execute_order_nb(
289
ProcessOrderState(100., 100., 0., 100., 10., 1100., 0, 0),
290
nb.order_nb(10, 10, min_size=100))
291
assert exec_state == ExecuteOrderState(cash=100.0, position=100.0, debt=0.0, free_cash=100.0)
292
assert_same_tuple(order_result, OrderResult(
293
size=np.nan, price=np.nan, fees=np.nan, side=-1, status=2, status_info=12))
294
exec_state, order_result = nb.execute_order_nb(
295
ProcessOrderState(100., 100., 0., 100., 10., 1100., 0, 0),
296
nb.order_nb(100, 10, allow_partial=False))
297
assert exec_state == ExecuteOrderState(cash=100.0, position=100.0, debt=0.0, free_cash=100.0)
298
assert_same_tuple(order_result, OrderResult(
299
size=np.nan, price=np.nan, fees=np.nan, side=-1, status=2, status_info=13))
300
exec_state, order_result = nb.execute_order_nb(
301
ProcessOrderState(100., 100., 0., 100., 10., 1100., 0, 0),
302
nb.order_nb(-10, 10, min_size=100))
303
assert exec_state == ExecuteOrderState(cash=100.0, position=100.0, debt=0.0, free_cash=100.0)
304
assert_same_tuple(order_result, OrderResult(
305
size=np.nan, price=np.nan, fees=np.nan, side=-1, status=2, status_info=12))
306
exec_state, order_result = nb.execute_order_nb(
307
ProcessOrderState(100., 100., 0., 100., 10., 1100., 0, 0),
308
nb.order_nb(-200, 10, direction=Direction.LongOnly, allow_partial=False))
309
assert exec_state == ExecuteOrderState(cash=100.0, position=100.0, debt=0.0, free_cash=100.0)
310
assert_same_tuple(order_result, OrderResult(
311
size=np.nan, price=np.nan, fees=np.nan, side=-1, status=2, status_info=13))
312
exec_state, order_result = nb.execute_order_nb(
313
ProcessOrderState(100., 100., 0., 100., 10., 1100., 0, 0),
314
nb.order_nb(-10, 10, fixed_fees=1000))
315
assert exec_state == ExecuteOrderState(cash=100.0, position=100.0, debt=0.0, free_cash=100.0)
316
assert_same_tuple(order_result, OrderResult(
317
size=np.nan, price=np.nan, fees=np.nan, side=-1, status=2, status_info=11))
318
319
# Calculations
320
exec_state, order_result = nb.execute_order_nb(
321
ProcessOrderState(100., 0., 0., 100., 10., 100., 0, 0),
322
nb.order_nb(10, 10, fees=0.1, fixed_fees=1, slippage=0.1))
323
assert exec_state == ExecuteOrderState(cash=0.0, position=8.18181818181818, debt=0.0, free_cash=0.0)
324
assert_same_tuple(order_result, OrderResult(
325
size=8.18181818181818, price=11.0, fees=10.000000000000014, side=0, status=0, status_info=-1))
326
exec_state, order_result = nb.execute_order_nb(
327
ProcessOrderState(100., 0., 0., 100., 10., 100., 0, 0),
328
nb.order_nb(100, 10, fees=0.1, fixed_fees=1, slippage=0.1))
329
assert exec_state == ExecuteOrderState(cash=0.0, position=8.18181818181818, debt=0.0, free_cash=0.0)
330
assert_same_tuple(order_result, OrderResult(
331
size=8.18181818181818, price=11.0, fees=10.000000000000014, side=0, status=0, status_info=-1))
332
exec_state, order_result = nb.execute_order_nb(
333
ProcessOrderState(100., 0., 0., 100., 10., 100., 0, 0),
334
nb.order_nb(-10, 10, fees=0.1, fixed_fees=1, slippage=0.1))
335
assert exec_state == ExecuteOrderState(cash=180.0, position=-10.0, debt=90.0, free_cash=0.0)
336
assert_same_tuple(order_result, OrderResult(
337
size=10.0, price=9.0, fees=10.0, side=1, status=0, status_info=-1))
338
exec_state, order_result = nb.execute_order_nb(
339
ProcessOrderState(100., 0., 0., 100., 10., 100., 0, 0),
340
nb.order_nb(-100, 10, fees=0.1, fixed_fees=1, slippage=0.1))
341
assert exec_state == ExecuteOrderState(cash=909.0, position=-100.0, debt=900.0, free_cash=-891.0)
342
assert_same_tuple(order_result, OrderResult(
343
size=100.0, price=9.0, fees=91.0, side=1, status=0, status_info=-1))
344
exec_state, order_result = nb.execute_order_nb(
345
ProcessOrderState(100., 0., 0., 100., 10., 100., 0, 0),
346
nb.order_nb(10, 10, fees=-0.1, fixed_fees=-1, slippage=0.1))
347
assert exec_state == ExecuteOrderState(cash=2.0, position=10.0, debt=0.0, free_cash=2.0)
348
assert_same_tuple(order_result, OrderResult(
349
size=10.0, price=11.0, fees=-12.0, side=0, status=0, status_info=-1))
350
351
exec_state, order_result = nb.execute_order_nb(
352
ProcessOrderState(100., 0., 0., 100., 10., 100., 0, 0),
353
nb.order_nb(10, 10, size_type=SizeType.TargetAmount))
354
assert exec_state == ExecuteOrderState(cash=0.0, position=10.0, debt=0.0, free_cash=0.0)
355
assert_same_tuple(order_result, OrderResult(
356
size=10., price=10.0, fees=0., side=0, status=0, status_info=-1))
357
exec_state, order_result = nb.execute_order_nb(
358
ProcessOrderState(100., 0., 0., 100., 10., 100., 0, 0),
359
nb.order_nb(-10, 10, size_type=SizeType.TargetAmount))
360
assert exec_state == ExecuteOrderState(cash=200.0, position=-10.0, debt=100.0, free_cash=0.0)
361
assert_same_tuple(order_result, OrderResult(
362
size=10., price=10.0, fees=0., side=1, status=0, status_info=-1))
363
364
exec_state, order_result = nb.execute_order_nb(
365
ProcessOrderState(100., 0., 0., 100., 10., 100., 0, 0),
366
nb.order_nb(100, 10, size_type=SizeType.Value))
367
assert exec_state == ExecuteOrderState(cash=0.0, position=10.0, debt=0.0, free_cash=0.0)
368
assert_same_tuple(order_result, OrderResult(
369
size=10., price=10.0, fees=0., side=0, status=0, status_info=-1))
370
exec_state, order_result = nb.execute_order_nb(
371
ProcessOrderState(100., 0., 0., 100., 10., 100., 0, 0),
372
nb.order_nb(-100, 10, size_type=SizeType.Value))
373
assert exec_state == ExecuteOrderState(cash=200.0, position=-10.0, debt=100.0, free_cash=0.0)
374
assert_same_tuple(order_result, OrderResult(
375
size=10., price=10.0, fees=0., side=1, status=0, status_info=-1))
376
377
exec_state, order_result = nb.execute_order_nb(
378
ProcessOrderState(100., 0., 0., 100., 10., 100., 0, 0),
379
nb.order_nb(100, 10, size_type=SizeType.TargetValue))
380
assert exec_state == ExecuteOrderState(cash=0.0, position=10.0, debt=0.0, free_cash=0.0)
381
assert_same_tuple(order_result, OrderResult(
382
size=10., price=10.0, fees=0., side=0, status=0, status_info=-1))
383
exec_state, order_result = nb.execute_order_nb(
384
ProcessOrderState(100., 0., 0., 100., 10., 100., 0, 0),
385
nb.order_nb(-100, 10, size_type=SizeType.TargetValue))
386
assert exec_state == ExecuteOrderState(cash=200.0, position=-10.0, debt=100.0, free_cash=0.0)
387
assert_same_tuple(order_result, OrderResult(
388
size=10., price=10.0, fees=0., side=1, status=0, status_info=-1))
389
390
exec_state, order_result = nb.execute_order_nb(
391
ProcessOrderState(100., 0., 0., 100., 10., 100., 0, 0),
392
nb.order_nb(1, 10, size_type=SizeType.TargetPercent))
393
assert exec_state == ExecuteOrderState(cash=0.0, position=10.0, debt=0.0, free_cash=0.0)
394
assert_same_tuple(order_result, OrderResult(
395
size=10., price=10.0, fees=0., side=0, status=0, status_info=-1))
396
exec_state, order_result = nb.execute_order_nb(
397
ProcessOrderState(100., 0., 0., 100., 10., 100., 0, 0),
398
nb.order_nb(-1, 10, size_type=SizeType.TargetPercent))
399
assert exec_state == ExecuteOrderState(cash=200.0, position=-10.0, debt=100.0, free_cash=0.0)
400
assert_same_tuple(order_result, OrderResult(
401
size=10., price=10.0, fees=0., side=1, status=0, status_info=-1))
402
403
exec_state, order_result = nb.execute_order_nb(
404
ProcessOrderState(50., 5., 0., 50., 10., 100., 0, 0),
405
nb.order_nb(1, 10, size_type=SizeType.Percent))
406
assert exec_state == ExecuteOrderState(cash=0.0, position=10.0, debt=0.0, free_cash=0.0)
407
assert_same_tuple(order_result, OrderResult(
408
size=5.0, price=10.0, fees=0.0, side=0, status=0, status_info=-1))
409
exec_state, order_result = nb.execute_order_nb(
410
ProcessOrderState(50., 5., 0., 50., 10., 100., 0, 0),
411
nb.order_nb(0.5, 10, size_type=SizeType.Percent))
412
assert exec_state == ExecuteOrderState(cash=25.0, position=7.5, debt=0.0, free_cash=25.0)
413
assert_same_tuple(order_result, OrderResult(
414
size=2.5, price=10.0, fees=0.0, side=0, status=0, status_info=-1))
415
exec_state, order_result = nb.execute_order_nb(
416
ProcessOrderState(50., 5., 0., 50., 10., 100., 0, 0),
417
nb.order_nb(-0.5, 10, size_type=SizeType.Percent))
418
assert exec_state == ExecuteOrderState(cash=125.0, position=-2.5, debt=25.0, free_cash=75.0)
419
assert_same_tuple(order_result, OrderResult(
420
size=7.5, price=10.0, fees=0.0, side=1, status=0, status_info=-1))
421
exec_state, order_result = nb.execute_order_nb(
422
ProcessOrderState(50., 5., 0., 50., 10., 100., 0, 0),
423
nb.order_nb(-1, 10, size_type=SizeType.Percent))
424
assert exec_state == ExecuteOrderState(cash=200.0, position=-10.0, debt=100.0, free_cash=0.0)
425
assert_same_tuple(order_result, OrderResult(
426
size=15.0, price=10.0, fees=0.0, side=1, status=0, status_info=-1))
427
exec_state, order_result = nb.execute_order_nb(
428
ProcessOrderState(50., 0., 0., 50., 10., 100., 0, 0),
429
nb.order_nb(1, 10, size_type=SizeType.Percent))
430
assert exec_state == ExecuteOrderState(cash=0.0, position=5.0, debt=0.0, free_cash=0.0)
431
assert_same_tuple(order_result, OrderResult(
432
size=5.0, price=10.0, fees=0.0, side=0, status=0, status_info=-1))
433
exec_state, order_result = nb.execute_order_nb(
434
ProcessOrderState(50., 0., 0., 50., 10., 100., 0, 0),
435
nb.order_nb(0.5, 10, size_type=SizeType.Percent))
436
assert exec_state == ExecuteOrderState(cash=25.0, position=2.5, debt=0.0, free_cash=25.0)
437
assert_same_tuple(order_result, OrderResult(
438
size=2.5, price=10.0, fees=0.0, side=0, status=0, status_info=-1))
439
exec_state, order_result = nb.execute_order_nb(
440
ProcessOrderState(50., 0., 0., 50., 10., 100., 0, 0),
441
nb.order_nb(-0.5, 10, size_type=SizeType.Percent))
442
assert exec_state == ExecuteOrderState(cash=75.0, position=-2.5, debt=25.0, free_cash=25.0)
443
assert_same_tuple(order_result, OrderResult(
444
size=2.5, price=10.0, fees=0.0, side=1, status=0, status_info=-1))
445
exec_state, order_result = nb.execute_order_nb(
446
ProcessOrderState(50., 0., 0., 50., 10., 100., 0, 0),
447
nb.order_nb(-1, 10, size_type=SizeType.Percent))
448
assert exec_state == ExecuteOrderState(cash=100.0, position=-5.0, debt=50.0, free_cash=0.0)
449
assert_same_tuple(order_result, OrderResult(
450
size=5.0, price=10.0, fees=0.0, side=1, status=0, status_info=-1))
451
exec_state, order_result = nb.execute_order_nb(
452
ProcessOrderState(50., -5., 0., 50., 10., 100., 0, 0),
453
nb.order_nb(1, 10, size_type=SizeType.Percent))
454
assert exec_state == ExecuteOrderState(cash=0.0, position=0.0, debt=0.0, free_cash=0.0)
455
assert_same_tuple(order_result, OrderResult(
456
size=5.0, price=10.0, fees=0.0, side=0, status=0, status_info=-1))
457
exec_state, order_result = nb.execute_order_nb(
458
ProcessOrderState(50., -5., 0., 50., 10., 100., 0, 0),
459
nb.order_nb(0.5, 10, size_type=SizeType.Percent))
460
assert exec_state == ExecuteOrderState(cash=25.0, position=-2.5, debt=0.0, free_cash=25.0)
461
assert_same_tuple(order_result, OrderResult(
462
size=2.5, price=10.0, fees=0.0, side=0, status=0, status_info=-1))
463
exec_state, order_result = nb.execute_order_nb(
464
ProcessOrderState(50., -5., 0., 50., 10., 100., 0, 0),
465
nb.order_nb(-0.5, 10, size_type=SizeType.Percent))
466
assert exec_state == ExecuteOrderState(cash=75.0, position=-7.5, debt=25.0, free_cash=25.0)
467
assert_same_tuple(order_result, OrderResult(
468
size=2.5, price=10.0, fees=0.0, side=1, status=0, status_info=-1))
469
exec_state, order_result = nb.execute_order_nb(
470
ProcessOrderState(50., -5., 0., 50., 10., 100., 0, 0),
471
nb.order_nb(-1, 10, size_type=SizeType.Percent))
472
assert exec_state == ExecuteOrderState(cash=100.0, position=-10.0, debt=50.0, free_cash=0.0)
473
assert_same_tuple(order_result, OrderResult(
474
size=5.0, price=10.0, fees=0.0, side=1, status=0, status_info=-1))
475
476
exec_state, order_result = nb.execute_order_nb(
477
ProcessOrderState(100., 0., 0., 100., 10., 100., 0, 0),
478
nb.order_nb(np.inf, 10))
479
assert exec_state == ExecuteOrderState(cash=0.0, position=10.0, debt=0.0, free_cash=0.0)
480
assert_same_tuple(order_result, OrderResult(
481
size=10., price=10.0, fees=0., side=0, status=0, status_info=-1))
482
exec_state, order_result = nb.execute_order_nb(
483
ProcessOrderState(100., -5., 0., 100., 10., 100., 0, 0),
484
nb.order_nb(np.inf, 10))
485
assert exec_state == ExecuteOrderState(cash=0.0, position=5.0, debt=0.0, free_cash=0.0)
486
assert_same_tuple(order_result, OrderResult(
487
size=10., price=10.0, fees=0., side=0, status=0, status_info=-1))
488
exec_state, order_result = nb.execute_order_nb(
489
ProcessOrderState(100., 0., 0., 100., 10., 100., 0, 0),
490
nb.order_nb(-np.inf, 10))
491
assert exec_state == ExecuteOrderState(cash=200.0, position=-10.0, debt=100.0, free_cash=0.0)
492
assert_same_tuple(order_result, OrderResult(
493
size=10., price=10.0, fees=0., side=1, status=0, status_info=-1))
494
exec_state, order_result = nb.execute_order_nb(
495
ProcessOrderState(150., -5., 0., 150., 10., 100., 0, 0),
496
nb.order_nb(-np.inf, 10))
497
assert exec_state == ExecuteOrderState(cash=300.0, position=-20.0, debt=150.0, free_cash=0.0)
498
assert_same_tuple(order_result, OrderResult(
499
size=15.0, price=10.0, fees=0.0, side=1, status=0, status_info=-1))
500
501
exec_state, order_result = nb.execute_order_nb(
502
ProcessOrderState(100., 0., 0., 50., 10., 100., 0, 0),
503
nb.order_nb(10, 10, lock_cash=True))
504
assert exec_state == ExecuteOrderState(cash=50.0, position=5.0, debt=0.0, free_cash=0.0)
505
assert_same_tuple(order_result, OrderResult(
506
size=5.0, price=10.0, fees=0.0, side=0, status=0, status_info=-1))
507
exec_state, order_result = nb.execute_order_nb(
508
ProcessOrderState(1000., -5., 50., 50., 10., 100., 0, 0),
509
nb.order_nb(10, 17.5, lock_cash=True))
510
assert exec_state == ExecuteOrderState(cash=850.0, position=3.571428571428571, debt=0.0, free_cash=0.0)
511
assert_same_tuple(order_result, OrderResult(
512
size=8.571428571428571, price=17.5, fees=0.0, side=0, status=0, status_info=-1))
513
exec_state, order_result = nb.execute_order_nb(
514
ProcessOrderState(100., -5., 50., 50., 10., 100., 0, 0),
515
nb.order_nb(10, 100, lock_cash=True))
516
assert exec_state == ExecuteOrderState(cash=37.5, position=-4.375, debt=43.75, free_cash=0.0)
517
assert_same_tuple(order_result, OrderResult(
518
size=0.625, price=100.0, fees=0.0, side=0, status=0, status_info=-1))
519
520
exec_state, order_result = nb.execute_order_nb(
521
ProcessOrderState(0., 10., 0., -50., 10., 100., 0, 0),
522
nb.order_nb(-20, 10, lock_cash=True))
523
assert exec_state == ExecuteOrderState(cash=150.0, position=-5.0, debt=50.0, free_cash=0.0)
524
assert_same_tuple(order_result, OrderResult(
525
size=15.0, price=10.0, fees=0.0, side=1, status=0, status_info=-1))
526
exec_state, order_result = nb.execute_order_nb(
527
ProcessOrderState(0., 1., 0., -50., 10., 100., 0, 0),
528
nb.order_nb(-10, 10, lock_cash=True))
529
assert exec_state == ExecuteOrderState(cash=10.0, position=0.0, debt=0.0, free_cash=-40.0)
530
assert_same_tuple(order_result, OrderResult(
531
size=1.0, price=10.0, fees=0.0, side=1, status=0, status_info=-1))
532
exec_state, order_result = nb.execute_order_nb(
533
ProcessOrderState(0., 0., 0., -100., 10., 100., 0, 0),
534
nb.order_nb(-10, 10, lock_cash=True))
535
assert exec_state == ExecuteOrderState(cash=0.0, position=0.0, debt=0.0, free_cash=-100.0)
536
assert_same_tuple(order_result, OrderResult(
537
size=np.nan, price=np.nan, fees=np.nan, side=-1, status=2, status_info=6))
538
exec_state, order_result = nb.execute_order_nb(
539
ProcessOrderState(0., 0., 0., 100., 10., 100., 0, 0),
540
nb.order_nb(-20, 10, fees=0.1, slippage=0.1, fixed_fees=1., lock_cash=True))
541
assert exec_state == ExecuteOrderState(cash=80.0, position=-10.0, debt=90.0, free_cash=0.0)
542
assert_same_tuple(order_result, OrderResult(
543
size=10.0, price=9.0, fees=10.0, side=1, status=0, status_info=-1))
544
545
546
def test_build_call_seq_nb():
547
group_lens = np.array([1, 2, 3, 4])
548
np.testing.assert_array_equal(
549
nb.build_call_seq_nb((10, 10), group_lens, CallSeqType.Default),
550
nb.build_call_seq((10, 10), group_lens, CallSeqType.Default)
551
)
552
np.testing.assert_array_equal(
553
nb.build_call_seq_nb((10, 10), group_lens, CallSeqType.Reversed),
554
nb.build_call_seq((10, 10), group_lens, CallSeqType.Reversed)
555
)
556
set_seed(seed)
557
out1 = nb.build_call_seq_nb((10, 10), group_lens, CallSeqType.Random)
558
set_seed(seed)
559
out2 = nb.build_call_seq((10, 10), group_lens, CallSeqType.Random)
560
np.testing.assert_array_equal(out1, out2)
561
562
563
# ############# from_orders ############# #
564
565
order_size = pd.Series([np.inf, -np.inf, np.nan, np.inf, -np.inf], index=price.index)
566
order_size_wide = order_size.vbt.tile(3, keys=['a', 'b', 'c'])
567
order_size_one = pd.Series([1, -1, np.nan, 1, -1], index=price.index)
568
569
570
def from_orders_both(close=price, size=order_size, **kwargs):
571
return vbt.Portfolio.from_orders(close, size, direction='both', **kwargs)
572
573
574
def from_orders_longonly(close=price, size=order_size, **kwargs):
575
return vbt.Portfolio.from_orders(close, size, direction='longonly', **kwargs)
576
577
578
def from_orders_shortonly(close=price, size=order_size, **kwargs):
579
return vbt.Portfolio.from_orders(close, size, direction='shortonly', **kwargs)
580
581
582
class TestFromOrders:
583
def test_one_column(self):
584
record_arrays_close(
585
from_orders_both().order_records,
586
np.array([
587
(0, 0, 0, 100.0, 1.0, 0.0, 0), (1, 0, 1, 200.0, 2.0, 0.0, 1), (2, 0, 3, 100.0, 4.0, 0.0, 0)
588
], dtype=order_dt)
589
)
590
record_arrays_close(
591
from_orders_longonly().order_records,
592
np.array([
593
(0, 0, 0, 100.0, 1.0, 0.0, 0), (1, 0, 1, 100.0, 2.0, 0.0, 1), (2, 0, 3, 50.0, 4.0, 0.0, 0),
594
(3, 0, 4, 50.0, 5.0, 0.0, 1)
595
], dtype=order_dt)
596
)
597
record_arrays_close(
598
from_orders_shortonly().order_records,
599
np.array([
600
(0, 0, 0, 100.0, 1.0, 0.0, 1), (1, 0, 1, 100.0, 2.0, 0.0, 0)
601
], dtype=order_dt)
602
)
603
pf = from_orders_both()
604
pd.testing.assert_index_equal(
605
pf.wrapper.index,
606
pd.DatetimeIndex(['2020-01-01', '2020-01-02', '2020-01-03', '2020-01-04', '2020-01-05'])
607
)
608
pd.testing.assert_index_equal(
609
pf.wrapper.columns,
610
pd.Index([0], dtype='int64')
611
)
612
assert pf.wrapper.ndim == 1
613
assert pf.wrapper.freq == day_dt
614
assert pf.wrapper.grouper.group_by is None
615
616
def test_multiple_columns(self):
617
record_arrays_close(
618
from_orders_both(close=price_wide).order_records,
619
np.array([
620
(0, 0, 0, 100.0, 1.0, 0.0, 0), (1, 0, 1, 200.0, 2.0, 0.0, 1), (2, 0, 3, 100.0, 4.0, 0.0, 0),
621
(3, 1, 0, 100.0, 1.0, 0.0, 0), (4, 1, 1, 200.0, 2.0, 0.0, 1), (5, 1, 3, 100.0, 4.0, 0.0, 0),
622
(6, 2, 0, 100.0, 1.0, 0.0, 0), (7, 2, 1, 200.0, 2.0, 0.0, 1), (8, 2, 3, 100.0, 4.0, 0.0, 0)
623
], dtype=order_dt)
624
)
625
record_arrays_close(
626
from_orders_longonly(close=price_wide).order_records,
627
np.array([
628
(0, 0, 0, 100.0, 1.0, 0.0, 0), (1, 0, 1, 100.0, 2.0, 0.0, 1), (2, 0, 3, 50.0, 4.0, 0.0, 0),
629
(3, 0, 4, 50.0, 5.0, 0.0, 1), (4, 1, 0, 100.0, 1.0, 0.0, 0), (5, 1, 1, 100.0, 2.0, 0.0, 1),
630
(6, 1, 3, 50.0, 4.0, 0.0, 0), (7, 1, 4, 50.0, 5.0, 0.0, 1), (8, 2, 0, 100.0, 1.0, 0.0, 0),
631
(9, 2, 1, 100.0, 2.0, 0.0, 1), (10, 2, 3, 50.0, 4.0, 0.0, 0), (11, 2, 4, 50.0, 5.0, 0.0, 1)
632
], dtype=order_dt)
633
)
634
record_arrays_close(
635
from_orders_shortonly(close=price_wide).order_records,
636
np.array([
637
(0, 0, 0, 100.0, 1.0, 0.0, 1), (1, 0, 1, 100.0, 2.0, 0.0, 0), (2, 1, 0, 100.0, 1.0, 0.0, 1),
638
(3, 1, 1, 100.0, 2.0, 0.0, 0), (4, 2, 0, 100.0, 1.0, 0.0, 1), (5, 2, 1, 100.0, 2.0, 0.0, 0)
639
], dtype=order_dt)
640
)
641
pf = from_orders_both(close=price_wide)
642
pd.testing.assert_index_equal(
643
pf.wrapper.index,
644
pd.DatetimeIndex(['2020-01-01', '2020-01-02', '2020-01-03', '2020-01-04', '2020-01-05'])
645
)
646
pd.testing.assert_index_equal(
647
pf.wrapper.columns,
648
pd.Index(['a', 'b', 'c'], dtype='object')
649
)
650
assert pf.wrapper.ndim == 2
651
assert pf.wrapper.freq == day_dt
652
assert pf.wrapper.grouper.group_by is None
653
654
def test_size_inf(self):
655
record_arrays_close(
656
from_orders_both(size=[[np.inf, -np.inf]]).order_records,
657
np.array([
658
(0, 0, 0, 100.0, 1.0, 0.0, 0), (1, 1, 0, 100.0, 1.0, 0.0, 1)
659
], dtype=order_dt)
660
)
661
record_arrays_close(
662
from_orders_longonly(size=[[np.inf, -np.inf]]).order_records,
663
np.array([
664
(0, 0, 0, 100.0, 1.0, 0.0, 0)
665
], dtype=order_dt)
666
)
667
record_arrays_close(
668
from_orders_shortonly(size=[[np.inf, -np.inf]]).order_records,
669
np.array([
670
(0, 0, 0, 100.0, 1.0, 0.0, 1)
671
], dtype=order_dt)
672
)
673
674
def test_size_granularity(self):
675
record_arrays_close(
676
from_orders_both(fees=0.1, fixed_fees=0.1, size_granularity=1).order_records,
677
np.array([
678
(0, 0, 0, 90., 1., 9.1, 0), (1, 0, 1, 164., 2., 32.9, 1),
679
(2, 0, 3, 67., 4., 26.9, 0)
680
], dtype=order_dt)
681
)
682
record_arrays_close(
683
from_orders_longonly(fees=0.1, fixed_fees=0.1, size_granularity=1).order_records,
684
np.array([
685
(0, 0, 0, 90.0, 1.0, 9.1, 0), (1, 0, 1, 90.0, 2.0, 18.1, 1),
686
(2, 0, 3, 36.0, 4.0, 14.5, 0), (3, 0, 4, 36.0, 5.0, 18.1, 1)
687
], dtype=order_dt)
688
)
689
record_arrays_close(
690
from_orders_shortonly(fees=0.1, fixed_fees=0.1, size_granularity=1).order_records,
691
np.array([
692
(0, 0, 0, 90., 1., 9.1, 1), (1, 0, 1, 82., 2., 16.5, 0)
693
], dtype=order_dt)
694
)
695
696
def test_price(self):
697
record_arrays_close(
698
from_orders_both(price=price * 1.01).order_records,
699
np.array([
700
(0, 0, 0, 99.00990099009901, 1.01, 0.0, 0), (1, 0, 1, 198.01980198019803, 2.02, 0.0, 1),
701
(2, 0, 3, 99.00990099009901, 4.04, 0.0, 0)
702
], dtype=order_dt)
703
)
704
record_arrays_close(
705
from_orders_longonly(price=price * 1.01).order_records,
706
np.array([
707
(0, 0, 0, 99.00990099009901, 1.01, 0.0, 0), (1, 0, 1, 99.00990099009901, 2.02, 0.0, 1),
708
(2, 0, 3, 49.504950495049506, 4.04, 0.0, 0), (3, 0, 4, 49.504950495049506, 5.05, 0.0, 1)
709
], dtype=order_dt)
710
)
711
record_arrays_close(
712
from_orders_shortonly(price=price * 1.01).order_records,
713
np.array([
714
(0, 0, 0, 99.00990099009901, 1.01, 0.0, 1), (1, 0, 1, 99.00990099009901, 2.02, 0.0, 0)
715
], dtype=order_dt)
716
)
717
record_arrays_close(
718
from_orders_both(price=np.inf).order_records,
719
np.array([
720
(0, 0, 0, 100.0, 1.0, 0.0, 0), (1, 0, 1, 200.0, 2.0, 0.0, 1), (2, 0, 3, 100.0, 4.0, 0.0, 0)
721
], dtype=order_dt)
722
)
723
record_arrays_close(
724
from_orders_longonly(price=np.inf).order_records,
725
np.array([
726
(0, 0, 0, 100.0, 1.0, 0.0, 0), (1, 0, 1, 100.0, 2.0, 0.0, 1),
727
(2, 0, 3, 50.0, 4.0, 0.0, 0), (3, 0, 4, 50.0, 5.0, 0.0, 1)
728
], dtype=order_dt)
729
)
730
record_arrays_close(
731
from_orders_shortonly(price=np.inf).order_records,
732
np.array([
733
(0, 0, 0, 100.0, 1.0, 0.0, 1), (1, 0, 1, 100.0, 2.0, 0.0, 0)
734
], dtype=order_dt)
735
)
736
record_arrays_close(
737
from_orders_both(price=-np.inf).order_records,
738
np.array([
739
(0, 0, 1, 100.0, 1.0, 0.0, 1), (1, 0, 3, 66.66666666666667, 3.0, 0.0, 0)
740
], dtype=order_dt)
741
)
742
record_arrays_close(
743
from_orders_longonly(price=-np.inf).order_records,
744
np.array([
745
(0, 0, 3, 33.333333333333336, 3.0, 0.0, 0), (1, 0, 4, 33.333333333333336, 4.0, 0.0, 1)
746
], dtype=order_dt)
747
)
748
record_arrays_close(
749
from_orders_shortonly(price=-np.inf).order_records,
750
np.array([
751
(0, 0, 3, 33.333333333333336, 3.0, 0.0, 1), (1, 0, 4, 33.333333333333336, 4.0, 0.0, 0)
752
], dtype=order_dt)
753
)
754
755
def test_val_price(self):
756
price_nan = pd.Series([1, 2, np.nan, 4, 5], index=price.index)
757
record_arrays_close(
758
from_orders_both(close=price_nan, size=order_size_one, val_price=np.inf,
759
size_type='value').order_records,
760
from_orders_both(close=price_nan, size=order_size_one, val_price=price,
761
size_type='value').order_records
762
)
763
record_arrays_close(
764
from_orders_longonly(close=price_nan, size=order_size_one, val_price=np.inf,
765
size_type='value').order_records,
766
from_orders_longonly(close=price_nan, size=order_size_one, val_price=price,
767
size_type='value').order_records
768
)
769
record_arrays_close(
770
from_orders_shortonly(close=price_nan, size=order_size_one, val_price=np.inf,
771
size_type='value').order_records,
772
from_orders_shortonly(close=price_nan, size=order_size_one, val_price=price,
773
size_type='value').order_records
774
)
775
shift_price = price_nan.ffill().shift(1)
776
record_arrays_close(
777
from_orders_both(close=price_nan, size=order_size_one, val_price=-np.inf,
778
size_type='value').order_records,
779
from_orders_both(close=price_nan, size=order_size_one, val_price=shift_price,
780
size_type='value').order_records
781
)
782
record_arrays_close(
783
from_orders_longonly(close=price_nan, size=order_size_one, val_price=-np.inf,
784
size_type='value').order_records,
785
from_orders_longonly(close=price_nan, size=order_size_one, val_price=shift_price,
786
size_type='value').order_records
787
)
788
record_arrays_close(
789
from_orders_shortonly(close=price_nan, size=order_size_one, val_price=-np.inf,
790
size_type='value').order_records,
791
from_orders_shortonly(close=price_nan, size=order_size_one, val_price=shift_price,
792
size_type='value').order_records
793
)
794
record_arrays_close(
795
from_orders_both(close=price_nan, size=order_size_one, val_price=np.inf,
796
size_type='value', ffill_val_price=False).order_records,
797
from_orders_both(close=price_nan, size=order_size_one, val_price=price_nan,
798
size_type='value', ffill_val_price=False).order_records
799
)
800
record_arrays_close(
801
from_orders_longonly(close=price_nan, size=order_size_one, val_price=np.inf,
802
size_type='value', ffill_val_price=False).order_records,
803
from_orders_longonly(close=price_nan, size=order_size_one, val_price=price_nan,
804
size_type='value', ffill_val_price=False).order_records
805
)
806
record_arrays_close(
807
from_orders_shortonly(close=price_nan, size=order_size_one, val_price=np.inf,
808
size_type='value', ffill_val_price=False).order_records,
809
from_orders_shortonly(close=price_nan, size=order_size_one, val_price=price_nan,
810
size_type='value', ffill_val_price=False).order_records
811
)
812
shift_price_nan = price_nan.shift(1)
813
record_arrays_close(
814
from_orders_both(close=price_nan, size=order_size_one, val_price=-np.inf,
815
size_type='value', ffill_val_price=False).order_records,
816
from_orders_both(close=price_nan, size=order_size_one, val_price=shift_price_nan,
817
size_type='value', ffill_val_price=False).order_records
818
)
819
record_arrays_close(
820
from_orders_longonly(close=price_nan, size=order_size_one, val_price=-np.inf,
821
size_type='value', ffill_val_price=False).order_records,
822
from_orders_longonly(close=price_nan, size=order_size_one, val_price=shift_price_nan,
823
size_type='value', ffill_val_price=False).order_records
824
)
825
record_arrays_close(
826
from_orders_shortonly(close=price_nan, size=order_size_one, val_price=-np.inf,
827
size_type='value', ffill_val_price=False).order_records,
828
from_orders_shortonly(close=price_nan, size=order_size_one, val_price=shift_price_nan,
829
size_type='value', ffill_val_price=False).order_records
830
)
831
832
def test_fees(self):
833
record_arrays_close(
834
from_orders_both(size=order_size_one, fees=[[-0.1, 0., 0.1, 1.]]).order_records,
835
np.array([
836
(0, 0, 0, 1.0, 1.0, -0.1, 0), (1, 0, 1, 1.0, 2.0, -0.2, 1), (2, 0, 3, 1.0, 4.0, -0.4, 0),
837
(3, 0, 4, 1.0, 5.0, -0.5, 1), (4, 1, 0, 1.0, 1.0, 0.0, 0), (5, 1, 1, 1.0, 2.0, 0.0, 1),
838
(6, 1, 3, 1.0, 4.0, 0.0, 0), (7, 1, 4, 1.0, 5.0, 0.0, 1), (8, 2, 0, 1.0, 1.0, 0.1, 0),
839
(9, 2, 1, 1.0, 2.0, 0.2, 1), (10, 2, 3, 1.0, 4.0, 0.4, 0), (11, 2, 4, 1.0, 5.0, 0.5, 1),
840
(12, 3, 0, 1.0, 1.0, 1.0, 0), (13, 3, 1, 1.0, 2.0, 2.0, 1), (14, 3, 3, 1.0, 4.0, 4.0, 0),
841
(15, 3, 4, 1.0, 5.0, 5.0, 1)
842
], dtype=order_dt)
843
)
844
record_arrays_close(
845
from_orders_longonly(size=order_size_one, fees=[[-0.1, 0., 0.1, 1.]]).order_records,
846
np.array([
847
(0, 0, 0, 1.0, 1.0, -0.1, 0), (1, 0, 1, 1.0, 2.0, -0.2, 1), (2, 0, 3, 1.0, 4.0, -0.4, 0),
848
(3, 0, 4, 1.0, 5.0, -0.5, 1), (4, 1, 0, 1.0, 1.0, 0.0, 0), (5, 1, 1, 1.0, 2.0, 0.0, 1),
849
(6, 1, 3, 1.0, 4.0, 0.0, 0), (7, 1, 4, 1.0, 5.0, 0.0, 1), (8, 2, 0, 1.0, 1.0, 0.1, 0),
850
(9, 2, 1, 1.0, 2.0, 0.2, 1), (10, 2, 3, 1.0, 4.0, 0.4, 0), (11, 2, 4, 1.0, 5.0, 0.5, 1),
851
(12, 3, 0, 1.0, 1.0, 1.0, 0), (13, 3, 1, 1.0, 2.0, 2.0, 1), (14, 3, 3, 1.0, 4.0, 4.0, 0),
852
(15, 3, 4, 1.0, 5.0, 5.0, 1)
853
], dtype=order_dt)
854
)
855
record_arrays_close(
856
from_orders_shortonly(size=order_size_one, fees=[[-0.1, 0., 0.1, 1.]]).order_records,
857
np.array([
858
(0, 0, 0, 1.0, 1.0, -0.1, 1), (1, 0, 1, 1.0, 2.0, -0.2, 0), (2, 0, 3, 1.0, 4.0, -0.4, 1),
859
(3, 0, 4, 1.0, 5.0, -0.5, 0), (4, 1, 0, 1.0, 1.0, 0.0, 1), (5, 1, 1, 1.0, 2.0, 0.0, 0),
860
(6, 1, 3, 1.0, 4.0, 0.0, 1), (7, 1, 4, 1.0, 5.0, 0.0, 0), (8, 2, 0, 1.0, 1.0, 0.1, 1),
861
(9, 2, 1, 1.0, 2.0, 0.2, 0), (10, 2, 3, 1.0, 4.0, 0.4, 1), (11, 2, 4, 1.0, 5.0, 0.5, 0),
862
(12, 3, 0, 1.0, 1.0, 1.0, 1), (13, 3, 1, 1.0, 2.0, 2.0, 0), (14, 3, 3, 1.0, 4.0, 4.0, 1),
863
(15, 3, 4, 1.0, 5.0, 5.0, 0)
864
], dtype=order_dt)
865
)
866
867
def test_fixed_fees(self):
868
record_arrays_close(
869
from_orders_both(size=order_size_one, fixed_fees=[[-0.1, 0., 0.1, 1.]]).order_records,
870
np.array([
871
(0, 0, 0, 1.0, 1.0, -0.1, 0), (1, 0, 1, 1.0, 2.0, -0.1, 1), (2, 0, 3, 1.0, 4.0, -0.1, 0),
872
(3, 0, 4, 1.0, 5.0, -0.1, 1), (4, 1, 0, 1.0, 1.0, 0.0, 0), (5, 1, 1, 1.0, 2.0, 0.0, 1),
873
(6, 1, 3, 1.0, 4.0, 0.0, 0), (7, 1, 4, 1.0, 5.0, 0.0, 1), (8, 2, 0, 1.0, 1.0, 0.1, 0),
874
(9, 2, 1, 1.0, 2.0, 0.1, 1), (10, 2, 3, 1.0, 4.0, 0.1, 0), (11, 2, 4, 1.0, 5.0, 0.1, 1),
875
(12, 3, 0, 1.0, 1.0, 1.0, 0), (13, 3, 1, 1.0, 2.0, 1.0, 1), (14, 3, 3, 1.0, 4.0, 1.0, 0),
876
(15, 3, 4, 1.0, 5.0, 1.0, 1)
877
], dtype=order_dt)
878
)
879
record_arrays_close(
880
from_orders_longonly(size=order_size_one, fixed_fees=[[-0.1, 0., 0.1, 1.]]).order_records,
881
np.array([
882
(0, 0, 0, 1.0, 1.0, -0.1, 0), (1, 0, 1, 1.0, 2.0, -0.1, 1), (2, 0, 3, 1.0, 4.0, -0.1, 0),
883
(3, 0, 4, 1.0, 5.0, -0.1, 1), (4, 1, 0, 1.0, 1.0, 0.0, 0), (5, 1, 1, 1.0, 2.0, 0.0, 1),
884
(6, 1, 3, 1.0, 4.0, 0.0, 0), (7, 1, 4, 1.0, 5.0, 0.0, 1), (8, 2, 0, 1.0, 1.0, 0.1, 0),
885
(9, 2, 1, 1.0, 2.0, 0.1, 1), (10, 2, 3, 1.0, 4.0, 0.1, 0), (11, 2, 4, 1.0, 5.0, 0.1, 1),
886
(12, 3, 0, 1.0, 1.0, 1.0, 0), (13, 3, 1, 1.0, 2.0, 1.0, 1), (14, 3, 3, 1.0, 4.0, 1.0, 0),
887
(15, 3, 4, 1.0, 5.0, 1.0, 1)
888
], dtype=order_dt)
889
)
890
record_arrays_close(
891
from_orders_shortonly(size=order_size_one, fixed_fees=[[-0.1, 0., 0.1, 1.]]).order_records,
892
np.array([
893
(0, 0, 0, 1.0, 1.0, -0.1, 1), (1, 0, 1, 1.0, 2.0, -0.1, 0), (2, 0, 3, 1.0, 4.0, -0.1, 1),
894
(3, 0, 4, 1.0, 5.0, -0.1, 0), (4, 1, 0, 1.0, 1.0, 0.0, 1), (5, 1, 1, 1.0, 2.0, 0.0, 0),
895
(6, 1, 3, 1.0, 4.0, 0.0, 1), (7, 1, 4, 1.0, 5.0, 0.0, 0), (8, 2, 0, 1.0, 1.0, 0.1, 1),
896
(9, 2, 1, 1.0, 2.0, 0.1, 0), (10, 2, 3, 1.0, 4.0, 0.1, 1), (11, 2, 4, 1.0, 5.0, 0.1, 0),
897
(12, 3, 0, 1.0, 1.0, 1.0, 1), (13, 3, 1, 1.0, 2.0, 1.0, 0), (14, 3, 3, 1.0, 4.0, 1.0, 1),
898
(15, 3, 4, 1.0, 5.0, 1.0, 0)
899
], dtype=order_dt)
900
)
901
902
def test_slippage(self):
903
record_arrays_close(
904
from_orders_both(size=order_size_one, slippage=[[0., 0.1, 1.]]).order_records,
905
np.array([
906
(0, 0, 0, 1.0, 1.0, 0.0, 0), (1, 0, 1, 1.0, 2.0, 0.0, 1), (2, 0, 3, 1.0, 4.0, 0.0, 0),
907
(3, 0, 4, 1.0, 5.0, 0.0, 1), (4, 1, 0, 1.0, 1.1, 0.0, 0), (5, 1, 1, 1.0, 1.8, 0.0, 1),
908
(6, 1, 3, 1.0, 4.4, 0.0, 0), (7, 1, 4, 1.0, 4.5, 0.0, 1), (8, 2, 0, 1.0, 2.0, 0.0, 0),
909
(9, 2, 1, 1.0, 0.0, 0.0, 1), (10, 2, 3, 1.0, 8.0, 0.0, 0), (11, 2, 4, 1.0, 0.0, 0.0, 1)
910
], dtype=order_dt)
911
)
912
record_arrays_close(
913
from_orders_longonly(size=order_size_one, slippage=[[0., 0.1, 1.]]).order_records,
914
np.array([
915
(0, 0, 0, 1.0, 1.0, 0.0, 0), (1, 0, 1, 1.0, 2.0, 0.0, 1), (2, 0, 3, 1.0, 4.0, 0.0, 0),
916
(3, 0, 4, 1.0, 5.0, 0.0, 1), (4, 1, 0, 1.0, 1.1, 0.0, 0), (5, 1, 1, 1.0, 1.8, 0.0, 1),
917
(6, 1, 3, 1.0, 4.4, 0.0, 0), (7, 1, 4, 1.0, 4.5, 0.0, 1), (8, 2, 0, 1.0, 2.0, 0.0, 0),
918
(9, 2, 1, 1.0, 0.0, 0.0, 1), (10, 2, 3, 1.0, 8.0, 0.0, 0), (11, 2, 4, 1.0, 0.0, 0.0, 1)
919
], dtype=order_dt)
920
)
921
record_arrays_close(
922
from_orders_shortonly(size=order_size_one, slippage=[[0., 0.1, 1.]]).order_records,
923
np.array([
924
(0, 0, 0, 1.0, 1.0, 0.0, 1), (1, 0, 1, 1.0, 2.0, 0.0, 0), (2, 0, 3, 1.0, 4.0, 0.0, 1),
925
(3, 0, 4, 1.0, 5.0, 0.0, 0), (4, 1, 0, 1.0, 0.9, 0.0, 1), (5, 1, 1, 1.0, 2.2, 0.0, 0),
926
(6, 1, 3, 1.0, 3.6, 0.0, 1), (7, 1, 4, 1.0, 5.5, 0.0, 0), (8, 2, 0, 1.0, 0.0, 0.0, 1),
927
(9, 2, 1, 1.0, 4.0, 0.0, 0), (10, 2, 3, 1.0, 0.0, 0.0, 1), (11, 2, 4, 1.0, 10.0, 0.0, 0)
928
], dtype=order_dt)
929
)
930
931
def test_min_size(self):
932
record_arrays_close(
933
from_orders_both(size=order_size_one, min_size=[[0., 1., 2.]]).order_records,
934
np.array([
935
(0, 0, 0, 1.0, 1.0, 0.0, 0), (1, 0, 1, 1.0, 2.0, 0.0, 1), (2, 0, 3, 1.0, 4.0, 0.0, 0),
936
(3, 0, 4, 1.0, 5.0, 0.0, 1), (4, 1, 0, 1.0, 1.0, 0.0, 0), (5, 1, 1, 1.0, 2.0, 0.0, 1),
937
(6, 1, 3, 1.0, 4.0, 0.0, 0), (7, 1, 4, 1.0, 5.0, 0.0, 1)
938
], dtype=order_dt)
939
)
940
record_arrays_close(
941
from_orders_longonly(size=order_size_one, min_size=[[0., 1., 2.]]).order_records,
942
np.array([
943
(0, 0, 0, 1.0, 1.0, 0.0, 0), (1, 0, 1, 1.0, 2.0, 0.0, 1), (2, 0, 3, 1.0, 4.0, 0.0, 0),
944
(3, 0, 4, 1.0, 5.0, 0.0, 1), (4, 1, 0, 1.0, 1.0, 0.0, 0), (5, 1, 1, 1.0, 2.0, 0.0, 1),
945
(6, 1, 3, 1.0, 4.0, 0.0, 0), (7, 1, 4, 1.0, 5.0, 0.0, 1)
946
], dtype=order_dt)
947
)
948
record_arrays_close(
949
from_orders_shortonly(size=order_size_one, min_size=[[0., 1., 2.]]).order_records,
950
np.array([
951
(0, 0, 0, 1.0, 1.0, 0.0, 1), (1, 0, 1, 1.0, 2.0, 0.0, 0), (2, 0, 3, 1.0, 4.0, 0.0, 1),
952
(3, 0, 4, 1.0, 5.0, 0.0, 0), (4, 1, 0, 1.0, 1.0, 0.0, 1), (5, 1, 1, 1.0, 2.0, 0.0, 0),
953
(6, 1, 3, 1.0, 4.0, 0.0, 1), (7, 1, 4, 1.0, 5.0, 0.0, 0)
954
], dtype=order_dt)
955
)
956
957
def test_max_size(self):
958
record_arrays_close(
959
from_orders_both(size=order_size_one, max_size=[[0.5, 1., np.inf]]).order_records,
960
np.array([
961
(0, 0, 0, 0.5, 1.0, 0.0, 0), (1, 0, 1, 0.5, 2.0, 0.0, 1), (2, 0, 3, 0.5, 4.0, 0.0, 0),
962
(3, 0, 4, 0.5, 5.0, 0.0, 1), (4, 1, 0, 1.0, 1.0, 0.0, 0), (5, 1, 1, 1.0, 2.0, 0.0, 1),
963
(6, 1, 3, 1.0, 4.0, 0.0, 0), (7, 1, 4, 1.0, 5.0, 0.0, 1), (8, 2, 0, 1.0, 1.0, 0.0, 0),
964
(9, 2, 1, 1.0, 2.0, 0.0, 1), (10, 2, 3, 1.0, 4.0, 0.0, 0), (11, 2, 4, 1.0, 5.0, 0.0, 1)
965
], dtype=order_dt)
966
)
967
record_arrays_close(
968
from_orders_longonly(size=order_size_one, max_size=[[0.5, 1., np.inf]]).order_records,
969
np.array([
970
(0, 0, 0, 0.5, 1.0, 0.0, 0), (1, 0, 1, 0.5, 2.0, 0.0, 1), (2, 0, 3, 0.5, 4.0, 0.0, 0),
971
(3, 0, 4, 0.5, 5.0, 0.0, 1), (4, 1, 0, 1.0, 1.0, 0.0, 0), (5, 1, 1, 1.0, 2.0, 0.0, 1),
972
(6, 1, 3, 1.0, 4.0, 0.0, 0), (7, 1, 4, 1.0, 5.0, 0.0, 1), (8, 2, 0, 1.0, 1.0, 0.0, 0),
973
(9, 2, 1, 1.0, 2.0, 0.0, 1), (10, 2, 3, 1.0, 4.0, 0.0, 0), (11, 2, 4, 1.0, 5.0, 0.0, 1)
974
], dtype=order_dt)
975
)
976
record_arrays_close(
977
from_orders_shortonly(size=order_size_one, max_size=[[0.5, 1., np.inf]]).order_records,
978
np.array([
979
(0, 0, 0, 0.5, 1.0, 0.0, 1), (1, 0, 1, 0.5, 2.0, 0.0, 0), (2, 0, 3, 0.5, 4.0, 0.0, 1),
980
(3, 0, 4, 0.5, 5.0, 0.0, 0), (4, 1, 0, 1.0, 1.0, 0.0, 1), (5, 1, 1, 1.0, 2.0, 0.0, 0),
981
(6, 1, 3, 1.0, 4.0, 0.0, 1), (7, 1, 4, 1.0, 5.0, 0.0, 0), (8, 2, 0, 1.0, 1.0, 0.0, 1),
982
(9, 2, 1, 1.0, 2.0, 0.0, 0), (10, 2, 3, 1.0, 4.0, 0.0, 1), (11, 2, 4, 1.0, 5.0, 0.0, 0)
983
], dtype=order_dt)
984
)
985
986
def test_reject_prob(self):
987
record_arrays_close(
988
from_orders_both(size=order_size_one, reject_prob=[[0., 0.5, 1.]], seed=42).order_records,
989
np.array([
990
(0, 0, 0, 1.0, 1.0, 0.0, 0), (1, 0, 1, 1.0, 2.0, 0.0, 1), (2, 0, 3, 1.0, 4.0, 0.0, 0),
991
(3, 0, 4, 1.0, 5.0, 0.0, 1), (4, 1, 1, 1.0, 2.0, 0.0, 1), (5, 1, 3, 1.0, 4.0, 0.0, 0),
992
(6, 1, 4, 1.0, 5.0, 0.0, 1)
993
], dtype=order_dt)
994
)
995
record_arrays_close(
996
from_orders_longonly(size=order_size_one, reject_prob=[[0., 0.5, 1.]], seed=42).order_records,
997
np.array([
998
(0, 0, 0, 1.0, 1.0, 0.0, 0), (1, 0, 1, 1.0, 2.0, 0.0, 1), (2, 0, 3, 1.0, 4.0, 0.0, 0),
999
(3, 0, 4, 1.0, 5.0, 0.0, 1), (4, 1, 3, 1.0, 4.0, 0.0, 0), (5, 1, 4, 1.0, 5.0, 0.0, 1)
1000
], dtype=order_dt)
1001
)
1002
record_arrays_close(
1003
from_orders_shortonly(size=order_size_one, reject_prob=[[0., 0.5, 1.]], seed=42).order_records,
1004
np.array([
1005
(0, 0, 0, 1.0, 1.0, 0.0, 1), (1, 0, 1, 1.0, 2.0, 0.0, 0), (2, 0, 3, 1.0, 4.0, 0.0, 1),
1006
(3, 0, 4, 1.0, 5.0, 0.0, 0), (4, 1, 3, 1.0, 4.0, 0.0, 1), (5, 1, 4, 1.0, 5.0, 0.0, 0)
1007
], dtype=order_dt)
1008
)
1009
1010
def test_lock_cash(self):
1011
pf = vbt.Portfolio.from_orders(
1012
pd.Series([1, 1]),
1013
pd.DataFrame([[-25, -25], [np.inf, np.inf]]),
1014
group_by=True, cash_sharing=True,
1015
lock_cash=False, fees=0.01, fixed_fees=1., slippage=0.01)
1016
np.testing.assert_array_equal(
1017
pf.asset_flow().values,
1018
np.array([
1019
[-25.0, -25.0],
1020
[143.12812469365747, 0.0]
1021
])
1022
)
1023
np.testing.assert_array_equal(
1024
pf.cash(group_by=False, in_sim_order=True).values,
1025
np.array([
1026
[123.5025, 147.005],
1027
[0.0, 0.0]
1028
])
1029
)
1030
np.testing.assert_array_equal(
1031
pf.cash(group_by=False, in_sim_order=True, free=True).values,
1032
np.array([
1033
[74.0025, 48.004999999999995],
1034
[-49.5, -49.5]
1035
])
1036
)
1037
pf = vbt.Portfolio.from_orders(
1038
pd.Series([1, 1]),
1039
pd.DataFrame([[-25, -25], [np.inf, np.inf]]),
1040
group_by=True, cash_sharing=True,
1041
lock_cash=True, fees=0.01, fixed_fees=1., slippage=0.01)
1042
np.testing.assert_array_equal(
1043
pf.asset_flow().values,
1044
np.array([
1045
[-25.0, -25.0],
1046
[94.6034702480149, 47.54435839623566]
1047
])
1048
)
1049
np.testing.assert_array_equal(
1050
pf.cash(group_by=False, in_sim_order=True).values,
1051
np.array([
1052
[123.5025, 147.005],
1053
[49.5, 0.0]
1054
])
1055
)
1056
np.testing.assert_array_equal(
1057
pf.cash(group_by=False, in_sim_order=True, free=True).values,
1058
np.array([
1059
[74.0025, 48.004999999999995],
1060
[0.0, 0.0]
1061
])
1062
)
1063
pf = vbt.Portfolio.from_orders(
1064
pd.Series([1, 100]),
1065
pd.DataFrame([[-25, -25], [np.inf, np.inf]]),
1066
group_by=True, cash_sharing=True,
1067
lock_cash=False, fees=0.01, fixed_fees=1., slippage=0.01)
1068
np.testing.assert_array_equal(
1069
pf.asset_flow().values,
1070
np.array([
1071
[-25.0, -25.0],
1072
[1.4312812469365748, 0.0]
1073
])
1074
)
1075
np.testing.assert_array_equal(
1076
pf.cash(group_by=False, in_sim_order=True).values,
1077
np.array([
1078
[123.5025, 147.005],
1079
[0.0, 0.0]
1080
])
1081
)
1082
np.testing.assert_array_equal(
1083
pf.cash(group_by=False, in_sim_order=True, free=True).values,
1084
np.array([
1085
[74.0025, 48.004999999999995],
1086
[-96.16606313106556, -96.16606313106556]
1087
])
1088
)
1089
pf = vbt.Portfolio.from_orders(
1090
pd.Series([1, 100]),
1091
pd.DataFrame([[-25, -25], [np.inf, np.inf]]),
1092
group_by=True, cash_sharing=True,
1093
lock_cash=True, fees=0.01, fixed_fees=1., slippage=0.01)
1094
np.testing.assert_array_equal(
1095
pf.asset_flow().values,
1096
np.array([
1097
[-25.0, -25.0],
1098
[0.4699090272918124, 0.0]
1099
])
1100
)
1101
np.testing.assert_array_equal(
1102
pf.cash(group_by=False, in_sim_order=True).values,
1103
np.array([
1104
[123.5025, 147.005],
1105
[98.06958012596222, 98.06958012596222]
1106
])
1107
)
1108
np.testing.assert_array_equal(
1109
pf.cash(group_by=False, in_sim_order=True, free=True).values,
1110
np.array([
1111
[74.0025, 48.004999999999995],
1112
[0.0, 0.0]
1113
])
1114
)
1115
pf = from_orders_both(size=order_size_one * 1000, lock_cash=[[False, True]])
1116
record_arrays_close(
1117
pf.order_records,
1118
np.array([
1119
(0, 0, 0, 100., 1., 0., 0), (1, 0, 1, 1000., 2., 0., 1),
1120
(2, 0, 3, 500., 4., 0., 0), (3, 0, 4, 1000., 5., 0., 1),
1121
(4, 1, 0, 100., 1., 0., 0), (5, 1, 1, 200., 2., 0., 1),
1122
(6, 1, 3, 100., 4., 0., 0)
1123
], dtype=order_dt)
1124
)
1125
np.testing.assert_array_equal(
1126
pf.cash(free=True).values,
1127
np.array([
1128
[0.0, 0.0],
1129
[-1600.0, 0.0],
1130
[-1600.0, 0.0],
1131
[-1600.0, 0.0],
1132
[-6600.0, 0.0]
1133
])
1134
)
1135
pf = from_orders_longonly(size=order_size_one * 1000, lock_cash=[[False, True]])
1136
record_arrays_close(
1137
pf.order_records,
1138
np.array([
1139
(0, 0, 0, 100., 1., 0., 0), (1, 0, 1, 100., 2., 0., 1),
1140
(2, 0, 3, 50., 4., 0., 0), (3, 0, 4, 50., 5., 0., 1),
1141
(4, 1, 0, 100., 1., 0., 0), (5, 1, 1, 100., 2., 0., 1),
1142
(6, 1, 3, 50., 4., 0., 0), (7, 1, 4, 50., 5., 0., 1)
1143
], dtype=order_dt)
1144
)
1145
np.testing.assert_array_equal(
1146
pf.cash(free=True).values,
1147
np.array([
1148
[0.0, 0.0],
1149
[200.0, 200.0],
1150
[200.0, 200.0],
1151
[0.0, 0.0],
1152
[250.0, 250.0]
1153
])
1154
)
1155
pf = from_orders_shortonly(size=order_size_one * 1000, lock_cash=[[False, True]])
1156
record_arrays_close(
1157
pf.order_records,
1158
np.array([
1159
(0, 0, 0, 1000., 1., 0., 1), (1, 0, 1, 550., 2., 0., 0),
1160
(2, 0, 3, 1000., 4., 0., 1), (3, 0, 4, 800., 5., 0., 0),
1161
(4, 1, 0, 100., 1., 0., 1), (5, 1, 1, 100., 2., 0., 0)
1162
], dtype=order_dt)
1163
)
1164
np.testing.assert_array_equal(
1165
pf.cash(free=True).values,
1166
np.array([
1167
[-900.0, 0.0],
1168
[-900.0, 0.0],
1169
[-900.0, 0.0],
1170
[-4900.0, 0.0],
1171
[-3989.6551724137926, 0.0]
1172
])
1173
)
1174
1175
def test_allow_partial(self):
1176
record_arrays_close(
1177
from_orders_both(size=order_size_one * 1000, allow_partial=[[True, False]]).order_records,
1178
np.array([
1179
(0, 0, 0, 100.0, 1.0, 0.0, 0), (1, 0, 1, 1000.0, 2.0, 0.0, 1), (2, 0, 3, 500.0, 4.0, 0.0, 0),
1180
(3, 0, 4, 1000.0, 5.0, 0.0, 1), (4, 1, 1, 1000.0, 2.0, 0.0, 1), (5, 1, 4, 1000.0, 5.0, 0.0, 1)
1181
], dtype=order_dt)
1182
)
1183
record_arrays_close(
1184
from_orders_longonly(size=order_size_one * 1000, allow_partial=[[True, False]]).order_records,
1185
np.array([
1186
(0, 0, 0, 100.0, 1.0, 0.0, 0), (1, 0, 1, 100.0, 2.0, 0.0, 1), (2, 0, 3, 50.0, 4.0, 0.0, 0),
1187
(3, 0, 4, 50.0, 5.0, 0.0, 1)
1188
], dtype=order_dt)
1189
)
1190
record_arrays_close(
1191
from_orders_shortonly(size=order_size_one * 1000, allow_partial=[[True, False]]).order_records,
1192
np.array([
1193
(0, 0, 0, 1000.0, 1.0, 0.0, 1), (1, 0, 1, 550.0, 2.0, 0.0, 0), (2, 0, 3, 1000.0, 4.0, 0.0, 1),
1194
(3, 0, 4, 800.0, 5.0, 0.0, 0), (4, 1, 0, 1000.0, 1.0, 0.0, 1), (5, 1, 3, 1000.0, 4.0, 0.0, 1),
1195
(6, 1, 4, 1000.0, 5.0, 0.0, 0)
1196
], dtype=order_dt)
1197
)
1198
record_arrays_close(
1199
from_orders_both(size=order_size, allow_partial=[[True, False]]).order_records,
1200
np.array([
1201
(0, 0, 0, 100.0, 1.0, 0.0, 0), (1, 0, 1, 200.0, 2.0, 0.0, 1), (2, 0, 3, 100.0, 4.0, 0.0, 0),
1202
(3, 1, 0, 100.0, 1.0, 0.0, 0), (4, 1, 1, 200.0, 2.0, 0.0, 1), (5, 1, 3, 100.0, 4.0, 0.0, 0)
1203
], dtype=order_dt)
1204
)
1205
record_arrays_close(
1206
from_orders_longonly(size=order_size, allow_partial=[[True, False]]).order_records,
1207
np.array([
1208
(0, 0, 0, 100.0, 1.0, 0.0, 0), (1, 0, 1, 100.0, 2.0, 0.0, 1), (2, 0, 3, 50.0, 4.0, 0.0, 0),
1209
(3, 0, 4, 50.0, 5.0, 0.0, 1), (4, 1, 0, 100.0, 1.0, 0.0, 0), (5, 1, 1, 100.0, 2.0, 0.0, 1),
1210
(6, 1, 3, 50.0, 4.0, 0.0, 0), (7, 1, 4, 50.0, 5.0, 0.0, 1)
1211
], dtype=order_dt)
1212
)
1213
record_arrays_close(
1214
from_orders_shortonly(size=order_size, allow_partial=[[True, False]]).order_records,
1215
np.array([
1216
(0, 0, 0, 100.0, 1.0, 0.0, 1), (1, 0, 1, 100.0, 2.0, 0.0, 0), (2, 1, 0, 100.0, 1.0, 0.0, 1),
1217
(3, 1, 1, 100.0, 2.0, 0.0, 0)
1218
], dtype=order_dt)
1219
)
1220
1221
def test_raise_reject(self):
1222
record_arrays_close(
1223
from_orders_both(size=order_size_one * 1000, allow_partial=True, raise_reject=True).order_records,
1224
np.array([
1225
(0, 0, 0, 100.0, 1.0, 0.0, 0), (1, 0, 1, 1000.0, 2.0, 0.0, 1), (2, 0, 3, 500.0, 4.0, 0.0, 0),
1226
(3, 0, 4, 1000.0, 5.0, 0.0, 1)
1227
], dtype=order_dt)
1228
)
1229
record_arrays_close(
1230
from_orders_longonly(size=order_size_one * 1000, allow_partial=True, raise_reject=True).order_records,
1231
np.array([
1232
(0, 0, 0, 100.0, 1.0, 0.0, 0), (1, 0, 1, 100.0, 2.0, 0.0, 1), (2, 0, 3, 50.0, 4.0, 0.0, 0),
1233
(3, 0, 4, 50.0, 5.0, 0.0, 1)
1234
], dtype=order_dt)
1235
)
1236
record_arrays_close(
1237
from_orders_shortonly(size=order_size_one * 1000, allow_partial=True, raise_reject=True).order_records,
1238
np.array([
1239
(0, 0, 0, 1000.0, 1.0, 0.0, 1), (1, 0, 1, 550.0, 2.0, 0.0, 0), (2, 0, 3, 1000.0, 4.0, 0.0, 1),
1240
(3, 0, 4, 800.0, 5.0, 0.0, 0)
1241
], dtype=order_dt)
1242
)
1243
with pytest.raises(Exception):
1244
_ = from_orders_both(size=order_size_one * 1000, allow_partial=False, raise_reject=True).order_records
1245
with pytest.raises(Exception):
1246
_ = from_orders_longonly(size=order_size_one * 1000, allow_partial=False, raise_reject=True).order_records
1247
with pytest.raises(Exception):
1248
_ = from_orders_shortonly(size=order_size_one * 1000, allow_partial=False, raise_reject=True).order_records
1249
1250
def test_log(self):
1251
record_arrays_close(
1252
from_orders_both(log=True).log_records,
1253
np.array([
1254
(0, 0, 0, 0, 100.0, 0.0, 0.0, 100.0, 1.0, 100.0, np.inf, 1.0, 0, 2,
1255
0.0, 0.0, 0.0, 1e-08, np.inf, np.nan, 0.0, False, True, False, True, 0.0,
1256
100.0, 0.0, 0.0, 1.0, 100.0, 100.0, 1.0, 0.0, 0, 0, -1, 0),
1257
(1, 0, 0, 1, 0.0, 100.0, 0.0, 0.0, 2.0, 200.0, -np.inf, 2.0, 0, 2,
1258
0.0, 0.0, 0.0, 1e-08, np.inf, np.nan, 0.0, False, True, False, True, 400.0,
1259
-100.0, 200.0, 0.0, 2.0, 200.0, 200.0, 2.0, 0.0, 1, 0, -1, 1),
1260
(2, 0, 0, 2, 400.0, -100.0, 200.0, 0.0, 3.0, 100.0, np.nan, 3.0, 0,
1261
2, 0.0, 0.0, 0.0, 1e-08, np.inf, np.nan, 0.0, False, True, False, True, 400.0,
1262
-100.0, 200.0, 0.0, 3.0, 100.0, np.nan, np.nan, np.nan, -1, 1, 0, -1),
1263
(3, 0, 0, 3, 400.0, -100.0, 200.0, 0.0, 4.0, 0.0, np.inf, 4.0, 0, 2,
1264
0.0, 0.0, 0.0, 1e-08, np.inf, np.nan, 0.0, False, True, False, True, 0.0, 0.0,
1265
0.0, 0.0, 4.0, 0.0, 100.0, 4.0, 0.0, 0, 0, -1, 2),
1266
(4, 0, 0, 4, 0.0, 0.0, 0.0, 0.0, 5.0, 0.0, -np.inf, 5.0, 0, 2, 0.0,
1267
0.0, 0.0, 1e-08, np.inf, np.nan, 0.0, False, True, False, True, 0.0, 0.0,
1268
0.0, 0.0, 5.0, 0.0, np.nan, np.nan, np.nan, -1, 2, 6, -1)
1269
], dtype=log_dt)
1270
)
1271
1272
def test_group_by(self):
1273
pf = from_orders_both(close=price_wide, group_by=np.array([0, 0, 1]))
1274
record_arrays_close(
1275
pf.order_records,
1276
np.array([
1277
(0, 0, 0, 100.0, 1.0, 0.0, 0), (1, 0, 1, 200.0, 2.0, 0.0, 1), (2, 0, 3, 100.0, 4.0, 0.0, 0),
1278
(3, 1, 0, 100.0, 1.0, 0.0, 0), (4, 1, 1, 200.0, 2.0, 0.0, 1), (5, 1, 3, 100.0, 4.0, 0.0, 0),
1279
(6, 2, 0, 100.0, 1.0, 0.0, 0), (7, 2, 1, 200.0, 2.0, 0.0, 1), (8, 2, 3, 100.0, 4.0, 0.0, 0)
1280
], dtype=order_dt)
1281
)
1282
pd.testing.assert_index_equal(
1283
pf.wrapper.grouper.group_by,
1284
pd.Index([0, 0, 1], dtype='int64')
1285
)
1286
pd.testing.assert_series_equal(
1287
pf.init_cash,
1288
pd.Series([200., 100.], index=pd.Index([0, 1], dtype='int64')).rename('init_cash')
1289
)
1290
assert not pf.cash_sharing
1291
1292
def test_cash_sharing(self):
1293
pf = from_orders_both(close=price_wide, group_by=np.array([0, 0, 1]), cash_sharing=True)
1294
record_arrays_close(
1295
pf.order_records,
1296
np.array([
1297
(0, 0, 0, 100., 1., 0., 0), (1, 0, 1, 200., 2., 0., 1),
1298
(2, 0, 3, 100., 4., 0., 0), (3, 2, 0, 100., 1., 0., 0),
1299
(4, 2, 1, 200., 2., 0., 1), (5, 2, 3, 100., 4., 0., 0)
1300
], dtype=order_dt)
1301
)
1302
pd.testing.assert_index_equal(
1303
pf.wrapper.grouper.group_by,
1304
pd.Index([0, 0, 1], dtype='int64')
1305
)
1306
pd.testing.assert_series_equal(
1307
pf.init_cash,
1308
pd.Series([100., 100.], index=pd.Index([0, 1], dtype='int64')).rename('init_cash')
1309
)
1310
assert pf.cash_sharing
1311
with pytest.raises(Exception):
1312
_ = pf.regroup(group_by=False)
1313
1314
def test_call_seq(self):
1315
pf = from_orders_both(close=price_wide, group_by=np.array([0, 0, 1]), cash_sharing=True)
1316
record_arrays_close(
1317
pf.order_records,
1318
np.array([
1319
(0, 0, 0, 100., 1., 0., 0), (1, 0, 1, 200., 2., 0., 1),
1320
(2, 0, 3, 100., 4., 0., 0), (3, 2, 0, 100., 1., 0., 0),
1321
(4, 2, 1, 200., 2., 0., 1), (5, 2, 3, 100., 4., 0., 0)
1322
], dtype=order_dt)
1323
)
1324
np.testing.assert_array_equal(
1325
pf.call_seq.values,
1326
np.array([
1327
[0, 1, 0],
1328
[0, 1, 0],
1329
[0, 1, 0],
1330
[0, 1, 0],
1331
[0, 1, 0]
1332
])
1333
)
1334
pf = from_orders_both(
1335
close=price_wide, group_by=np.array([0, 0, 1]),
1336
cash_sharing=True, call_seq='reversed')
1337
record_arrays_close(
1338
pf.order_records,
1339
np.array([
1340
(0, 1, 0, 100., 1., 0., 0), (1, 1, 1, 200., 2., 0., 1),
1341
(2, 1, 3, 100., 4., 0., 0), (3, 2, 0, 100., 1., 0., 0),
1342
(4, 2, 1, 200., 2., 0., 1), (5, 2, 3, 100., 4., 0., 0)
1343
], dtype=order_dt)
1344
)
1345
np.testing.assert_array_equal(
1346
pf.call_seq.values,
1347
np.array([
1348
[1, 0, 0],
1349
[1, 0, 0],
1350
[1, 0, 0],
1351
[1, 0, 0],
1352
[1, 0, 0]
1353
])
1354
)
1355
pf = from_orders_both(
1356
close=price_wide, group_by=np.array([0, 0, 1]),
1357
cash_sharing=True, call_seq='random', seed=seed)
1358
record_arrays_close(
1359
pf.order_records,
1360
np.array([
1361
(0, 1, 0, 100., 1., 0., 0), (1, 1, 1, 200., 2., 0., 1),
1362
(2, 1, 3, 100., 4., 0., 0), (3, 2, 0, 100., 1., 0., 0),
1363
(4, 2, 1, 200., 2., 0., 1), (5, 2, 3, 100., 4., 0., 0)
1364
], dtype=order_dt)
1365
)
1366
np.testing.assert_array_equal(
1367
pf.call_seq.values,
1368
np.array([
1369
[1, 0, 0],
1370
[0, 1, 0],
1371
[1, 0, 0],
1372
[1, 0, 0],
1373
[1, 0, 0]
1374
])
1375
)
1376
kwargs = dict(
1377
close=1.,
1378
size=pd.DataFrame([
1379
[0., 0., np.inf],
1380
[0., np.inf, -np.inf],
1381
[np.inf, -np.inf, 0.],
1382
[-np.inf, 0., np.inf],
1383
[0., np.inf, -np.inf],
1384
]),
1385
group_by=np.array([0, 0, 0]),
1386
cash_sharing=True,
1387
call_seq='auto'
1388
)
1389
pf = from_orders_both(**kwargs)
1390
record_arrays_close(
1391
pf.order_records,
1392
np.array([
1393
(0, 2, 0, 100., 1., 0., 0), (1, 2, 1, 200., 1., 0., 1),
1394
(2, 1, 1, 200., 1., 0., 0), (3, 1, 2, 200., 1., 0., 1),
1395
(4, 0, 2, 200., 1., 0., 0), (5, 0, 3, 200., 1., 0., 1),
1396
(6, 2, 3, 200., 1., 0., 0), (7, 2, 4, 200., 1., 0., 1),
1397
(8, 1, 4, 200., 1., 0., 0)
1398
], dtype=order_dt)
1399
)
1400
np.testing.assert_array_equal(
1401
pf.call_seq.values,
1402
np.array([
1403
[0, 1, 2],
1404
[2, 0, 1],
1405
[1, 2, 0],
1406
[0, 1, 2],
1407
[2, 0, 1]
1408
])
1409
)
1410
pf = from_orders_longonly(**kwargs)
1411
record_arrays_close(
1412
pf.order_records,
1413
np.array([
1414
(0, 2, 0, 100., 1., 0., 0), (1, 2, 1, 100., 1., 0., 1),
1415
(2, 1, 1, 100., 1., 0., 0), (3, 1, 2, 100., 1., 0., 1),
1416
(4, 0, 2, 100., 1., 0., 0), (5, 0, 3, 100., 1., 0., 1),
1417
(6, 2, 3, 100., 1., 0., 0), (7, 2, 4, 100., 1., 0., 1),
1418
(8, 1, 4, 100., 1., 0., 0)
1419
], dtype=order_dt)
1420
)
1421
np.testing.assert_array_equal(
1422
pf.call_seq.values,
1423
np.array([
1424
[0, 1, 2],
1425
[2, 0, 1],
1426
[1, 2, 0],
1427
[0, 1, 2],
1428
[2, 0, 1]
1429
])
1430
)
1431
pf = from_orders_shortonly(**kwargs)
1432
record_arrays_close(
1433
pf.order_records,
1434
np.array([
1435
(0, 2, 0, 100., 1., 0., 1), (1, 2, 1, 100., 1., 0., 0),
1436
(2, 0, 2, 100., 1., 0., 1), (3, 0, 3, 100., 1., 0., 0),
1437
(4, 1, 4, 100., 1., 0., 1)
1438
], dtype=order_dt)
1439
)
1440
np.testing.assert_array_equal(
1441
pf.call_seq.values,
1442
np.array([
1443
[2, 0, 1],
1444
[1, 0, 2],
1445
[0, 2, 1],
1446
[2, 1, 0],
1447
[1, 0, 2]
1448
])
1449
)
1450
1451
def test_value(self):
1452
record_arrays_close(
1453
from_orders_both(size=order_size_one, size_type='value').order_records,
1454
np.array([
1455
(0, 0, 0, 1.0, 1.0, 0.0, 0), (1, 0, 1, 0.5, 2.0, 0.0, 1),
1456
(2, 0, 3, 0.25, 4.0, 0.0, 0), (3, 0, 4, 0.2, 5.0, 0.0, 1)
1457
], dtype=order_dt)
1458
)
1459
record_arrays_close(
1460
from_orders_longonly(size=order_size_one, size_type='value').order_records,
1461
np.array([
1462
(0, 0, 0, 1.0, 1.0, 0.0, 0), (1, 0, 1, 0.5, 2.0, 0.0, 1),
1463
(2, 0, 3, 0.25, 4.0, 0.0, 0), (3, 0, 4, 0.2, 5.0, 0.0, 1)
1464
], dtype=order_dt)
1465
)
1466
record_arrays_close(
1467
from_orders_shortonly(size=order_size_one, size_type='value').order_records,
1468
np.array([
1469
(0, 0, 0, 1.0, 1.0, 0.0, 1), (1, 0, 1, 0.5, 2.0, 0.0, 0),
1470
(2, 0, 3, 0.25, 4.0, 0.0, 1), (3, 0, 4, 0.2, 5.0, 0.0, 0)
1471
], dtype=order_dt)
1472
)
1473
1474
def test_target_amount(self):
1475
record_arrays_close(
1476
from_orders_both(size=[[75., -75.]], size_type='targetamount').order_records,
1477
np.array([
1478
(0, 0, 0, 75.0, 1.0, 0.0, 0), (1, 1, 0, 75.0, 1.0, 0.0, 1)
1479
], dtype=order_dt)
1480
)
1481
record_arrays_close(
1482
from_orders_longonly(size=[[75., -75.]], size_type='targetamount').order_records,
1483
np.array([
1484
(0, 0, 0, 75.0, 1.0, 0.0, 0)
1485
], dtype=order_dt)
1486
)
1487
record_arrays_close(
1488
from_orders_shortonly(size=[[75., -75.]], size_type='targetamount').order_records,
1489
np.array([
1490
(0, 0, 0, 75.0, 1.0, 0.0, 1)
1491
], dtype=order_dt)
1492
)
1493
record_arrays_close(
1494
from_orders_both(
1495
close=price_wide, size=75., size_type='targetamount',
1496
group_by=np.array([0, 0, 0]), cash_sharing=True).order_records,
1497
np.array([
1498
(0, 0, 0, 75.0, 1.0, 0.0, 0), (1, 1, 0, 25.0, 1.0, 0.0, 0)
1499
], dtype=order_dt)
1500
)
1501
1502
def test_target_value(self):
1503
record_arrays_close(
1504
from_orders_both(size=[[50., -50.]], size_type='targetvalue').order_records,
1505
np.array([
1506
(0, 0, 0, 50.0, 1.0, 0.0, 0), (1, 0, 1, 25.0, 2.0, 0.0, 1),
1507
(2, 0, 2, 8.333333333333332, 3.0, 0.0, 1), (3, 0, 3, 4.166666666666668, 4.0, 0.0, 1),
1508
(4, 0, 4, 2.5, 5.0, 0.0, 1), (5, 1, 0, 50.0, 1.0, 0.0, 1),
1509
(6, 1, 1, 25.0, 2.0, 0.0, 0), (7, 1, 2, 8.333333333333332, 3.0, 0.0, 0),
1510
(8, 1, 3, 4.166666666666668, 4.0, 0.0, 0), (9, 1, 4, 2.5, 5.0, 0.0, 0)
1511
], dtype=order_dt)
1512
)
1513
record_arrays_close(
1514
from_orders_longonly(size=[[50., -50.]], size_type='targetvalue').order_records,
1515
np.array([
1516
(0, 0, 0, 50.0, 1.0, 0.0, 0), (1, 0, 1, 25.0, 2.0, 0.0, 1),
1517
(2, 0, 2, 8.333333333333332, 3.0, 0.0, 1), (3, 0, 3, 4.166666666666668, 4.0, 0.0, 1),
1518
(4, 0, 4, 2.5, 5.0, 0.0, 1)
1519
], dtype=order_dt)
1520
)
1521
record_arrays_close(
1522
from_orders_shortonly(size=[[50., -50.]], size_type='targetvalue').order_records,
1523
np.array([
1524
(0, 0, 0, 50.0, 1.0, 0.0, 1), (1, 0, 1, 25.0, 2.0, 0.0, 0),
1525
(2, 0, 2, 8.333333333333332, 3.0, 0.0, 0), (3, 0, 3, 4.166666666666668, 4.0, 0.0, 0),
1526
(4, 0, 4, 2.5, 5.0, 0.0, 0)
1527
], dtype=order_dt)
1528
)
1529
record_arrays_close(
1530
from_orders_both(
1531
close=price_wide, size=50., size_type='targetvalue',
1532
group_by=np.array([0, 0, 0]), cash_sharing=True).order_records,
1533
np.array([
1534
(0, 0, 0, 50.0, 1.0, 0.0, 0), (1, 1, 0, 50.0, 1.0, 0.0, 0),
1535
(2, 0, 1, 25.0, 2.0, 0.0, 1), (3, 1, 1, 25.0, 2.0, 0.0, 1),
1536
(4, 2, 1, 25.0, 2.0, 0.0, 0), (5, 0, 2, 8.333333333333332, 3.0, 0.0, 1),
1537
(6, 1, 2, 8.333333333333332, 3.0, 0.0, 1), (7, 2, 2, 8.333333333333332, 3.0, 0.0, 1),
1538
(8, 0, 3, 4.166666666666668, 4.0, 0.0, 1), (9, 1, 3, 4.166666666666668, 4.0, 0.0, 1),
1539
(10, 2, 3, 4.166666666666668, 4.0, 0.0, 1), (11, 0, 4, 2.5, 5.0, 0.0, 1),
1540
(12, 1, 4, 2.5, 5.0, 0.0, 1), (13, 2, 4, 2.5, 5.0, 0.0, 1)
1541
], dtype=order_dt)
1542
)
1543
1544
def test_target_percent(self):
1545
record_arrays_close(
1546
from_orders_both(size=[[0.5, -0.5]], size_type='targetpercent').order_records,
1547
np.array([
1548
(0, 0, 0, 50.0, 1.0, 0.0, 0), (1, 0, 1, 12.5, 2.0, 0.0, 1), (2, 0, 2, 6.25, 3.0, 0.0, 1),
1549
(3, 0, 3, 3.90625, 4.0, 0.0, 1), (4, 0, 4, 2.734375, 5.0, 0.0, 1), (5, 1, 0, 50.0, 1.0, 0.0, 1),
1550
(6, 1, 1, 37.5, 2.0, 0.0, 0), (7, 1, 2, 6.25, 3.0, 0.0, 0), (8, 1, 3, 2.34375, 4.0, 0.0, 0),
1551
(9, 1, 4, 1.171875, 5.0, 0.0, 0)
1552
], dtype=order_dt)
1553
)
1554
record_arrays_close(
1555
from_orders_longonly(size=[[0.5, -0.5]], size_type='targetpercent').order_records,
1556
np.array([
1557
(0, 0, 0, 50.0, 1.0, 0.0, 0), (1, 0, 1, 12.5, 2.0, 0.0, 1), (2, 0, 2, 6.25, 3.0, 0.0, 1),
1558
(3, 0, 3, 3.90625, 4.0, 0.0, 1), (4, 0, 4, 2.734375, 5.0, 0.0, 1)
1559
], dtype=order_dt)
1560
)
1561
record_arrays_close(
1562
from_orders_shortonly(size=[[0.5, -0.5]], size_type='targetpercent').order_records,
1563
np.array([
1564
(0, 0, 0, 50.0, 1.0, 0.0, 1), (1, 0, 1, 37.5, 2.0, 0.0, 0), (2, 0, 2, 6.25, 3.0, 0.0, 0),
1565
(3, 0, 3, 2.34375, 4.0, 0.0, 0), (4, 0, 4, 1.171875, 5.0, 0.0, 0)
1566
], dtype=order_dt)
1567
)
1568
record_arrays_close(
1569
from_orders_both(
1570
close=price_wide, size=0.5, size_type='targetpercent',
1571
group_by=np.array([0, 0, 0]), cash_sharing=True).order_records,
1572
np.array([
1573
(0, 0, 0, 50.0, 1.0, 0.0, 0), (1, 1, 0, 50.0, 1.0, 0.0, 0)
1574
], dtype=order_dt)
1575
)
1576
1577
def test_update_value(self):
1578
record_arrays_close(
1579
from_orders_both(size=0.5, size_type='targetpercent', fees=0.01, slippage=0.01,
1580
update_value=False).order_records,
1581
from_orders_both(size=0.5, size_type='targetpercent', fees=0.01, slippage=0.01,
1582
update_value=True).order_records
1583
)
1584
record_arrays_close(
1585
from_orders_both(
1586
close=price_wide, size=0.5, size_type='targetpercent', fees=0.01, slippage=0.01,
1587
group_by=np.array([0, 0, 0]), cash_sharing=True, update_value=False).order_records,
1588
np.array([
1589
(0, 0, 0, 50.0, 1.01, 0.505, 0),
1590
(1, 1, 0, 48.02960494069208, 1.01, 0.485099009900992, 0),
1591
(2, 0, 1, 0.9851975296539592, 1.98, 0.019506911087148394, 1),
1592
(3, 1, 1, 0.9465661198057499, 2.02, 0.019120635620076154, 0),
1593
(4, 0, 2, 0.019315704924103727, 2.9699999999999998, 0.0005736764362458806, 1),
1594
(5, 1, 2, 0.018558300554959377, 3.0300000000000002, 0.0005623165068152705, 0),
1595
(6, 0, 3, 0.00037870218456959037, 3.96, 1.4996606508955778e-05, 1),
1596
(7, 1, 3, 0.0003638525743521767, 4.04, 1.4699644003827875e-05, 0),
1597
(8, 0, 4, 7.424805112066224e-06, 4.95, 3.675278530472781e-07, 1),
1598
(9, 1, 4, 7.133664827307231e-06, 5.05, 3.6025007377901643e-07, 0)
1599
], dtype=order_dt)
1600
)
1601
record_arrays_close(
1602
from_orders_both(
1603
close=price_wide, size=0.5, size_type='targetpercent', fees=0.01, slippage=0.01,
1604
group_by=np.array([0, 0, 0]), cash_sharing=True, update_value=True).order_records,
1605
np.array([
1606
(0, 0, 0, 50.0, 1.01, 0.505, 0),
1607
(1, 1, 0, 48.02960494069208, 1.01, 0.485099009900992, 0),
1608
(2, 0, 1, 0.9851975296539592, 1.98, 0.019506911087148394, 1),
1609
(3, 1, 1, 0.7303208018821721, 2.02, 0.014752480198019875, 0),
1610
(4, 2, 1, 0.21624531792357785, 2.02, 0.0043681554220562635, 0),
1611
(5, 0, 2, 0.019315704924103727, 2.9699999999999998, 0.0005736764362458806, 1),
1612
(6, 1, 2, 0.009608602243410758, 2.9699999999999998, 0.00028537548662929945, 1),
1613
(7, 2, 2, 0.02779013180558861, 3.0300000000000002, 0.0008420409937093393, 0),
1614
(8, 0, 3, 0.0005670876809631409, 3.96, 2.2456672166140378e-05, 1),
1615
(9, 1, 3, 0.00037770350099464167, 3.96, 1.4957058639387809e-05, 1),
1616
(10, 2, 3, 0.0009077441794302741, 4.04, 3.6672864848982974e-05, 0),
1617
(11, 0, 4, 1.8523501267964093e-05, 4.95, 9.169133127642227e-07, 1),
1618
(12, 1, 4, 1.2972670177191503e-05, 4.95, 6.421471737709794e-07, 1),
1619
(13, 2, 4, 3.0261148547590434e-05, 5.05, 1.5281880016533242e-06, 0)
1620
], dtype=order_dt)
1621
)
1622
1623
def test_percent(self):
1624
record_arrays_close(
1625
from_orders_both(size=[[0.5, -0.5]], size_type='percent').order_records,
1626
np.array([
1627
(0, 0, 0, 50., 1., 0., 0), (1, 0, 1, 12.5, 2., 0., 0),
1628
(2, 0, 2, 4.16666667, 3., 0., 0), (3, 0, 3, 1.5625, 4., 0., 0),
1629
(4, 0, 4, 0.625, 5., 0., 0), (5, 1, 0, 50., 1., 0., 1),
1630
(6, 1, 1, 12.5, 2., 0., 1), (7, 1, 2, 4.16666667, 3., 0., 1),
1631
(8, 1, 3, 1.5625, 4., 0., 1), (9, 1, 4, 0.625, 5., 0., 1)
1632
], dtype=order_dt)
1633
)
1634
record_arrays_close(
1635
from_orders_longonly(size=[[0.5, -0.5]], size_type='percent').order_records,
1636
np.array([
1637
(0, 0, 0, 50., 1., 0., 0), (1, 0, 1, 12.5, 2., 0., 0),
1638
(2, 0, 2, 4.16666667, 3., 0., 0), (3, 0, 3, 1.5625, 4., 0., 0),
1639
(4, 0, 4, 0.625, 5., 0., 0)
1640
], dtype=order_dt)
1641
)
1642
record_arrays_close(
1643
from_orders_shortonly(size=[[0.5, -0.5]], size_type='percent').order_records,
1644
np.array([
1645
(0, 0, 0, 50., 1., 0., 1), (1, 0, 1, 12.5, 2., 0., 1),
1646
(2, 0, 2, 4.16666667, 3., 0., 1), (3, 0, 3, 1.5625, 4., 0., 1),
1647
(4, 0, 4, 0.625, 5., 0., 1)
1648
], dtype=order_dt)
1649
)
1650
record_arrays_close(
1651
from_orders_both(
1652
close=price_wide, size=0.5, size_type='percent',
1653
group_by=np.array([0, 0, 0]), cash_sharing=True).order_records,
1654
np.array([
1655
(0, 0, 0, 5.00000000e+01, 1., 0., 0), (1, 1, 0, 2.50000000e+01, 1., 0., 0),
1656
(2, 2, 0, 1.25000000e+01, 1., 0., 0), (3, 0, 1, 3.12500000e+00, 2., 0., 0),
1657
(4, 1, 1, 1.56250000e+00, 2., 0., 0), (5, 2, 1, 7.81250000e-01, 2., 0., 0),
1658
(6, 0, 2, 2.60416667e-01, 3., 0., 0), (7, 1, 2, 1.30208333e-01, 3., 0., 0),
1659
(8, 2, 2, 6.51041667e-02, 3., 0., 0), (9, 0, 3, 2.44140625e-02, 4., 0., 0),
1660
(10, 1, 3, 1.22070312e-02, 4., 0., 0), (11, 2, 3, 6.10351562e-03, 4., 0., 0),
1661
(12, 0, 4, 2.44140625e-03, 5., 0., 0), (13, 1, 4, 1.22070312e-03, 5., 0., 0),
1662
(14, 2, 4, 6.10351562e-04, 5., 0., 0)
1663
], dtype=order_dt)
1664
)
1665
1666
def test_auto_seq(self):
1667
target_hold_value = pd.DataFrame({
1668
'a': [0., 70., 30., 0., 70.],
1669
'b': [30., 0., 70., 30., 30.],
1670
'c': [70., 30., 0., 70., 0.]
1671
}, index=price.index)
1672
pd.testing.assert_frame_equal(
1673
from_orders_both(
1674
close=1., size=target_hold_value, size_type='targetvalue',
1675
group_by=np.array([0, 0, 0]), cash_sharing=True,
1676
call_seq='auto').asset_value(group_by=False),
1677
target_hold_value
1678
)
1679
pd.testing.assert_frame_equal(
1680
from_orders_both(
1681
close=1., size=target_hold_value / 100, size_type='targetpercent',
1682
group_by=np.array([0, 0, 0]), cash_sharing=True,
1683
call_seq='auto').asset_value(group_by=False),
1684
target_hold_value
1685
)
1686
1687
def test_max_orders(self):
1688
_ = from_orders_both(close=price_wide)
1689
_ = from_orders_both(close=price_wide, max_orders=9)
1690
with pytest.raises(Exception):
1691
_ = from_orders_both(close=price_wide, max_orders=8)
1692
1693
def test_max_logs(self):
1694
_ = from_orders_both(close=price_wide, log=True)
1695
_ = from_orders_both(close=price_wide, log=True, max_logs=15)
1696
with pytest.raises(Exception):
1697
_ = from_orders_both(close=price_wide, log=True, max_logs=14)
1698
1699
1700
# ############# from_signals ############# #
1701
1702
entries = pd.Series([True, True, True, False, False], index=price.index)
1703
entries_wide = entries.vbt.tile(3, keys=['a', 'b', 'c'])
1704
1705
exits = pd.Series([False, False, True, True, True], index=price.index)
1706
exits_wide = exits.vbt.tile(3, keys=['a', 'b', 'c'])
1707
1708
1709
def from_signals_both(close=price, entries=entries, exits=exits, **kwargs):
1710
return vbt.Portfolio.from_signals(close, entries, exits, direction='both', **kwargs)
1711
1712
1713
def from_signals_longonly(close=price, entries=entries, exits=exits, **kwargs):
1714
return vbt.Portfolio.from_signals(close, entries, exits, direction='longonly', **kwargs)
1715
1716
1717
def from_signals_shortonly(close=price, entries=entries, exits=exits, **kwargs):
1718
return vbt.Portfolio.from_signals(close, entries, exits, direction='shortonly', **kwargs)
1719
1720
1721
def from_ls_signals_both(close=price, entries=entries, exits=exits, **kwargs):
1722
return vbt.Portfolio.from_signals(close, entries, False, exits, False, **kwargs)
1723
1724
1725
def from_ls_signals_longonly(close=price, entries=entries, exits=exits, **kwargs):
1726
return vbt.Portfolio.from_signals(close, entries, exits, False, False, **kwargs)
1727
1728
1729
def from_ls_signals_shortonly(close=price, entries=entries, exits=exits, **kwargs):
1730
return vbt.Portfolio.from_signals(close, False, False, entries, exits, **kwargs)
1731
1732
1733
class TestFromSignals:
1734
@pytest.mark.parametrize(
1735
"test_ls",
1736
[False, True],
1737
)
1738
def test_one_column(self, test_ls):
1739
_from_signals_both = from_ls_signals_both if test_ls else from_signals_both
1740
_from_signals_longonly = from_ls_signals_longonly if test_ls else from_signals_longonly
1741
_from_signals_shortonly = from_ls_signals_shortonly if test_ls else from_signals_shortonly
1742
record_arrays_close(
1743
_from_signals_both().order_records,
1744
np.array([
1745
(0, 0, 0, 100., 1., 0., 0), (1, 0, 3, 200., 4., 0., 1)
1746
], dtype=order_dt)
1747
)
1748
record_arrays_close(
1749
_from_signals_longonly().order_records,
1750
np.array([
1751
(0, 0, 0, 100., 1., 0., 0), (1, 0, 3, 100., 4., 0., 1)
1752
], dtype=order_dt)
1753
)
1754
record_arrays_close(
1755
_from_signals_shortonly().order_records,
1756
np.array([
1757
(0, 0, 0, 100., 1., 0., 1), (1, 0, 3, 50., 4., 0., 0)
1758
], dtype=order_dt)
1759
)
1760
pf = _from_signals_both()
1761
pd.testing.assert_index_equal(
1762
pf.wrapper.index,
1763
pd.DatetimeIndex(['2020-01-01', '2020-01-02', '2020-01-03', '2020-01-04', '2020-01-05'])
1764
)
1765
pd.testing.assert_index_equal(
1766
pf.wrapper.columns,
1767
pd.Index([0], dtype='int64')
1768
)
1769
assert pf.wrapper.ndim == 1
1770
assert pf.wrapper.freq == day_dt
1771
assert pf.wrapper.grouper.group_by is None
1772
1773
@pytest.mark.parametrize(
1774
"test_ls",
1775
[False, True],
1776
)
1777
def test_multiple_columns(self, test_ls):
1778
_from_signals_both = from_ls_signals_both if test_ls else from_signals_both
1779
_from_signals_longonly = from_ls_signals_longonly if test_ls else from_signals_longonly
1780
_from_signals_shortonly = from_ls_signals_shortonly if test_ls else from_signals_shortonly
1781
record_arrays_close(
1782
_from_signals_both(close=price_wide).order_records,
1783
np.array([
1784
(0, 0, 0, 100., 1., 0., 0), (1, 0, 3, 200., 4., 0., 1),
1785
(2, 1, 0, 100., 1., 0., 0), (3, 1, 3, 200., 4., 0., 1),
1786
(4, 2, 0, 100., 1., 0., 0), (5, 2, 3, 200., 4., 0., 1)
1787
], dtype=order_dt)
1788
)
1789
record_arrays_close(
1790
_from_signals_longonly(close=price_wide).order_records,
1791
np.array([
1792
(0, 0, 0, 100., 1., 0., 0), (1, 0, 3, 100., 4., 0., 1),
1793
(2, 1, 0, 100., 1., 0., 0), (3, 1, 3, 100., 4., 0., 1),
1794
(4, 2, 0, 100., 1., 0., 0), (5, 2, 3, 100., 4., 0., 1)
1795
], dtype=order_dt)
1796
)
1797
record_arrays_close(
1798
_from_signals_shortonly(close=price_wide).order_records,
1799
np.array([
1800
(0, 0, 0, 100., 1., 0., 1), (1, 0, 3, 50., 4., 0., 0),
1801
(2, 1, 0, 100., 1., 0., 1), (3, 1, 3, 50., 4., 0., 0),
1802
(4, 2, 0, 100., 1., 0., 1), (5, 2, 3, 50., 4., 0., 0)
1803
], dtype=order_dt)
1804
)
1805
pf = _from_signals_both(close=price_wide)
1806
pd.testing.assert_index_equal(
1807
pf.wrapper.index,
1808
pd.DatetimeIndex(['2020-01-01', '2020-01-02', '2020-01-03', '2020-01-04', '2020-01-05'])
1809
)
1810
pd.testing.assert_index_equal(
1811
pf.wrapper.columns,
1812
pd.Index(['a', 'b', 'c'], dtype='object')
1813
)
1814
assert pf.wrapper.ndim == 2
1815
assert pf.wrapper.freq == day_dt
1816
assert pf.wrapper.grouper.group_by is None
1817
1818
def test_custom_signal_func(self):
1819
@njit
1820
def signal_func_nb(c, long_num_arr, short_num_arr):
1821
long_num = nb.get_elem_nb(c, long_num_arr)
1822
short_num = nb.get_elem_nb(c, short_num_arr)
1823
is_long_entry = long_num > 0
1824
is_long_exit = long_num < 0
1825
is_short_entry = short_num > 0
1826
is_short_exit = short_num < 0
1827
return is_long_entry, is_long_exit, is_short_entry, is_short_exit
1828
1829
pf_base = vbt.Portfolio.from_signals(
1830
pd.Series([1, 2, 3, 4, 5]),
1831
entries=pd.Series([True, False, False, False, False]),
1832
exits=pd.Series([False, False, True, False, False]),
1833
short_entries=pd.Series([False, True, False, True, False]),
1834
short_exits=pd.Series([False, False, False, False, True]),
1835
size=1,
1836
upon_opposite_entry='ignore'
1837
)
1838
pf = vbt.Portfolio.from_signals(
1839
pd.Series([1, 2, 3, 4, 5]),
1840
signal_func_nb=signal_func_nb,
1841
signal_args=(vbt.Rep('long_num_arr'), vbt.Rep('short_num_arr')),
1842
broadcast_named_args=dict(
1843
long_num_arr=pd.Series([1, 0, -1, 0, 0]),
1844
short_num_arr=pd.Series([0, 1, 0, 1, -1])
1845
),
1846
size=1,
1847
upon_opposite_entry='ignore'
1848
)
1849
record_arrays_close(
1850
pf_base.order_records,
1851
pf.order_records
1852
)
1853
1854
def test_amount(self):
1855
record_arrays_close(
1856
from_signals_both(size=[[0, 1, np.inf]], size_type='amount').order_records,
1857
np.array([
1858
(0, 1, 0, 1.0, 1.0, 0.0, 0), (1, 1, 3, 2.0, 4.0, 0.0, 1),
1859
(2, 2, 0, 100.0, 1.0, 0.0, 0), (3, 2, 3, 200.0, 4.0, 0.0, 1)
1860
], dtype=order_dt)
1861
)
1862
record_arrays_close(
1863
from_signals_longonly(size=[[0, 1, np.inf]], size_type='amount').order_records,
1864
np.array([
1865
(0, 1, 0, 1.0, 1.0, 0.0, 0), (1, 1, 3, 1.0, 4.0, 0.0, 1),
1866
(2, 2, 0, 100.0, 1.0, 0.0, 0), (3, 2, 3, 100.0, 4.0, 0.0, 1)
1867
], dtype=order_dt)
1868
)
1869
record_arrays_close(
1870
from_signals_shortonly(size=[[0, 1, np.inf]], size_type='amount').order_records,
1871
np.array([
1872
(0, 1, 0, 1.0, 1.0, 0.0, 1), (1, 1, 3, 1.0, 4.0, 0.0, 0),
1873
(2, 2, 0, 100.0, 1.0, 0.0, 1), (3, 2, 3, 50.0, 4.0, 0.0, 0)
1874
], dtype=order_dt)
1875
)
1876
1877
def test_value(self):
1878
record_arrays_close(
1879
from_signals_both(size=[[0, 1, np.inf]], size_type='value').order_records,
1880
np.array([
1881
(0, 1, 0, 1.0, 1.0, 0.0, 0), (1, 1, 3, 1.25, 4.0, 0.0, 1),
1882
(2, 2, 0, 100.0, 1.0, 0.0, 0), (3, 2, 3, 200.0, 4.0, 0.0, 1)
1883
], dtype=order_dt)
1884
)
1885
record_arrays_close(
1886
from_signals_longonly(size=[[0, 1, np.inf]], size_type='value').order_records,
1887
np.array([
1888
(0, 1, 0, 1.0, 1.0, 0.0, 0), (1, 1, 3, 1.0, 4.0, 0.0, 1),
1889
(2, 2, 0, 100.0, 1.0, 0.0, 0), (3, 2, 3, 100.0, 4.0, 0.0, 1)
1890
], dtype=order_dt)
1891
)
1892
record_arrays_close(
1893
from_signals_shortonly(size=[[0, 1, np.inf]], size_type='value').order_records,
1894
np.array([
1895
(0, 1, 0, 1.0, 1.0, 0.0, 1), (1, 1, 3, 1.0, 4.0, 0.0, 0),
1896
(2, 2, 0, 100.0, 1.0, 0.0, 1), (3, 2, 3, 50.0, 4.0, 0.0, 0)
1897
], dtype=order_dt)
1898
)
1899
1900
def test_percent(self):
1901
with pytest.raises(Exception):
1902
_ = from_signals_both(size=0.5, size_type='percent')
1903
record_arrays_close(
1904
from_signals_both(size=0.5, size_type='percent', upon_opposite_entry='close').order_records,
1905
np.array([
1906
(0, 0, 0, 50., 1., 0., 0), (1, 0, 3, 50., 4., 0., 1), (2, 0, 4, 25., 5., 0., 1)
1907
], dtype=order_dt)
1908
)
1909
record_arrays_close(
1910
from_signals_both(size=0.5, size_type='percent', upon_opposite_entry='close',
1911
accumulate=True).order_records,
1912
np.array([
1913
(0, 0, 0, 50.0, 1.0, 0.0, 0), (1, 0, 1, 12.5, 2.0, 0.0, 0),
1914
(2, 0, 3, 62.5, 4.0, 0.0, 1), (3, 0, 4, 27.5, 5.0, 0.0, 1)
1915
], dtype=order_dt)
1916
)
1917
record_arrays_close(
1918
from_signals_longonly(size=0.5, size_type='percent').order_records,
1919
np.array([
1920
(0, 0, 0, 50., 1., 0., 0), (1, 0, 3, 50., 4., 0., 1)
1921
], dtype=order_dt)
1922
)
1923
record_arrays_close(
1924
from_signals_shortonly(size=0.5, size_type='percent').order_records,
1925
np.array([
1926
(0, 0, 0, 50., 1., 0., 1), (1, 0, 3, 37.5, 4., 0., 0)
1927
], dtype=order_dt)
1928
)
1929
record_arrays_close(
1930
from_signals_longonly(
1931
close=price_wide, size=0.5, size_type='percent',
1932
group_by=np.array([0, 0, 0]), cash_sharing=True).order_records,
1933
np.array([
1934
(0, 0, 0, 50., 1., 0., 0), (1, 1, 0, 25., 1., 0., 0),
1935
(2, 2, 0, 12.5, 1., 0., 0), (3, 0, 3, 50., 4., 0., 1),
1936
(4, 1, 3, 25., 4., 0., 1), (5, 2, 3, 12.5, 4., 0., 1)
1937
], dtype=order_dt)
1938
)
1939
1940
def test_price(self):
1941
record_arrays_close(
1942
from_signals_both(price=price * 1.01).order_records,
1943
np.array([
1944
(0, 0, 0, 99.00990099009901, 1.01, 0.0, 0), (1, 0, 3, 198.01980198019803, 4.04, 0.0, 1)
1945
], dtype=order_dt)
1946
)
1947
record_arrays_close(
1948
from_signals_longonly(price=price * 1.01).order_records,
1949
np.array([
1950
(0, 0, 0, 99.00990099, 1.01, 0., 0), (1, 0, 3, 99.00990099, 4.04, 0., 1)
1951
], dtype=order_dt)
1952
)
1953
record_arrays_close(
1954
from_signals_shortonly(price=price * 1.01).order_records,
1955
np.array([
1956
(0, 0, 0, 99.00990099009901, 1.01, 0.0, 1), (1, 0, 3, 49.504950495049506, 4.04, 0.0, 0)
1957
], dtype=order_dt)
1958
)
1959
record_arrays_close(
1960
from_signals_both(price=np.inf).order_records,
1961
np.array([
1962
(0, 0, 0, 100.0, 1.0, 0.0, 0), (1, 0, 3, 200.0, 4.0, 0.0, 1)
1963
], dtype=order_dt)
1964
)
1965
record_arrays_close(
1966
from_signals_longonly(price=np.inf).order_records,
1967
np.array([
1968
(0, 0, 0, 100.0, 1.0, 0.0, 0), (1, 0, 3, 100.0, 4.0, 0.0, 1)
1969
], dtype=order_dt)
1970
)
1971
record_arrays_close(
1972
from_signals_shortonly(price=np.inf).order_records,
1973
np.array([
1974
(0, 0, 0, 100.0, 1.0, 0.0, 1), (1, 0, 3, 50.0, 4.0, 0.0, 0)
1975
], dtype=order_dt)
1976
)
1977
record_arrays_close(
1978
from_signals_both(price=-np.inf).order_records,
1979
np.array([
1980
(0, 0, 1, 100.0, 1.0, 0.0, 0), (1, 0, 3, 200.0, 3.0, 0.0, 1)
1981
], dtype=order_dt)
1982
)
1983
record_arrays_close(
1984
from_signals_longonly(price=-np.inf).order_records,
1985
np.array([
1986
(0, 0, 1, 100.0, 1.0, 0.0, 0), (1, 0, 3, 100.0, 3.0, 0.0, 1)
1987
], dtype=order_dt)
1988
)
1989
record_arrays_close(
1990
from_signals_shortonly(price=-np.inf).order_records,
1991
np.array([
1992
(0, 0, 1, 100.0, 1.0, 0.0, 1), (1, 0, 3, 66.66666666666667, 3.0, 0.0, 0)
1993
], dtype=order_dt)
1994
)
1995
1996
def test_val_price(self):
1997
price_nan = pd.Series([1, 2, np.nan, 4, 5], index=price.index)
1998
record_arrays_close(
1999
from_signals_both(close=price_nan, size=1, val_price=np.inf,
2000
size_type='value').order_records,
2001
from_signals_both(close=price_nan, size=1, val_price=price,
2002
size_type='value').order_records
2003
)
2004
record_arrays_close(
2005
from_signals_longonly(close=price_nan, size=1, val_price=np.inf,
2006
size_type='value').order_records,
2007
from_signals_longonly(close=price_nan, size=1, val_price=price,
2008
size_type='value').order_records
2009
)
2010
record_arrays_close(
2011
from_signals_shortonly(close=price_nan, size=1, val_price=np.inf,
2012
size_type='value').order_records,
2013
from_signals_shortonly(close=price_nan, size=1, val_price=price,
2014
size_type='value').order_records
2015
)
2016
shift_price = price_nan.ffill().shift(1)
2017
record_arrays_close(
2018
from_signals_both(close=price_nan, size=1, val_price=-np.inf,
2019
size_type='value').order_records,
2020
from_signals_both(close=price_nan, size=1, val_price=shift_price,
2021
size_type='value').order_records
2022
)
2023
record_arrays_close(
2024
from_signals_longonly(close=price_nan, size=1, val_price=-np.inf,
2025
size_type='value').order_records,
2026
from_signals_longonly(close=price_nan, size=1, val_price=shift_price,
2027
size_type='value').order_records
2028
)
2029
record_arrays_close(
2030
from_signals_shortonly(close=price_nan, size=1, val_price=-np.inf,
2031
size_type='value').order_records,
2032
from_signals_shortonly(close=price_nan, size=1, val_price=shift_price,
2033
size_type='value').order_records
2034
)
2035
record_arrays_close(
2036
from_signals_both(close=price_nan, size=1, val_price=np.inf,
2037
size_type='value', ffill_val_price=False).order_records,
2038
from_signals_both(close=price_nan, size=1, val_price=price_nan,
2039
size_type='value', ffill_val_price=False).order_records
2040
)
2041
record_arrays_close(
2042
from_signals_longonly(close=price_nan, size=1, val_price=np.inf,
2043
size_type='value', ffill_val_price=False).order_records,
2044
from_signals_longonly(close=price_nan, size=1, val_price=price_nan,
2045
size_type='value', ffill_val_price=False).order_records
2046
)
2047
record_arrays_close(
2048
from_signals_shortonly(close=price_nan, size=1, val_price=np.inf,
2049
size_type='value', ffill_val_price=False).order_records,
2050
from_signals_shortonly(close=price_nan, size=1, val_price=price_nan,
2051
size_type='value', ffill_val_price=False).order_records
2052
)
2053
shift_price_nan = price_nan.shift(1)
2054
record_arrays_close(
2055
from_signals_both(close=price_nan, size=1, val_price=-np.inf,
2056
size_type='value', ffill_val_price=False).order_records,
2057
from_signals_both(close=price_nan, size=1, val_price=shift_price_nan,
2058
size_type='value', ffill_val_price=False).order_records
2059
)
2060
record_arrays_close(
2061
from_signals_longonly(close=price_nan, size=1, val_price=-np.inf,
2062
size_type='value', ffill_val_price=False).order_records,
2063
from_signals_longonly(close=price_nan, size=1, val_price=shift_price_nan,
2064
size_type='value', ffill_val_price=False).order_records
2065
)
2066
record_arrays_close(
2067
from_signals_shortonly(close=price_nan, size=1, val_price=-np.inf,
2068
size_type='value', ffill_val_price=False).order_records,
2069
from_signals_shortonly(close=price_nan, size=1, val_price=shift_price_nan,
2070
size_type='value', ffill_val_price=False).order_records
2071
)
2072
2073
def test_fees(self):
2074
record_arrays_close(
2075
from_signals_both(size=1, fees=[[-0.1, 0., 0.1, 1.]]).order_records,
2076
np.array([
2077
(0, 0, 0, 1.0, 1.0, -0.1, 0), (1, 0, 3, 2.0, 4.0, -0.8, 1), (2, 1, 0, 1.0, 1.0, 0.0, 0),
2078
(3, 1, 3, 2.0, 4.0, 0.0, 1), (4, 2, 0, 1.0, 1.0, 0.1, 0), (5, 2, 3, 2.0, 4.0, 0.8, 1),
2079
(6, 3, 0, 1.0, 1.0, 1.0, 0), (7, 3, 3, 2.0, 4.0, 8.0, 1)
2080
], dtype=order_dt)
2081
)
2082
record_arrays_close(
2083
from_signals_longonly(size=1, fees=[[-0.1, 0., 0.1, 1.]]).order_records,
2084
np.array([
2085
(0, 0, 0, 1.0, 1.0, -0.1, 0), (1, 0, 3, 1.0, 4.0, -0.4, 1), (2, 1, 0, 1.0, 1.0, 0.0, 0),
2086
(3, 1, 3, 1.0, 4.0, 0.0, 1), (4, 2, 0, 1.0, 1.0, 0.1, 0), (5, 2, 3, 1.0, 4.0, 0.4, 1),
2087
(6, 3, 0, 1.0, 1.0, 1.0, 0), (7, 3, 3, 1.0, 4.0, 4.0, 1)
2088
], dtype=order_dt)
2089
)
2090
record_arrays_close(
2091
from_signals_shortonly(size=1, fees=[[-0.1, 0., 0.1, 1.]]).order_records,
2092
np.array([
2093
(0, 0, 0, 1.0, 1.0, -0.1, 1), (1, 0, 3, 1.0, 4.0, -0.4, 0), (2, 1, 0, 1.0, 1.0, 0.0, 1),
2094
(3, 1, 3, 1.0, 4.0, 0.0, 0), (4, 2, 0, 1.0, 1.0, 0.1, 1), (5, 2, 3, 1.0, 4.0, 0.4, 0),
2095
(6, 3, 0, 1.0, 1.0, 1.0, 1), (7, 3, 3, 1.0, 4.0, 4.0, 0)
2096
], dtype=order_dt)
2097
)
2098
2099
def test_fixed_fees(self):
2100
record_arrays_close(
2101
from_signals_both(size=1, fixed_fees=[[-0.1, 0., 0.1, 1.]]).order_records,
2102
np.array([
2103
(0, 0, 0, 1.0, 1.0, -0.1, 0), (1, 0, 3, 2.0, 4.0, -0.1, 1), (2, 1, 0, 1.0, 1.0, 0.0, 0),
2104
(3, 1, 3, 2.0, 4.0, 0.0, 1), (4, 2, 0, 1.0, 1.0, 0.1, 0), (5, 2, 3, 2.0, 4.0, 0.1, 1),
2105
(6, 3, 0, 1.0, 1.0, 1.0, 0), (7, 3, 3, 2.0, 4.0, 1.0, 1)
2106
], dtype=order_dt)
2107
)
2108
record_arrays_close(
2109
from_signals_longonly(size=1, fixed_fees=[[-0.1, 0., 0.1, 1.]]).order_records,
2110
np.array([
2111
(0, 0, 0, 1.0, 1.0, -0.1, 0), (1, 0, 3, 1.0, 4.0, -0.1, 1), (2, 1, 0, 1.0, 1.0, 0.0, 0),
2112
(3, 1, 3, 1.0, 4.0, 0.0, 1), (4, 2, 0, 1.0, 1.0, 0.1, 0), (5, 2, 3, 1.0, 4.0, 0.1, 1),
2113
(6, 3, 0, 1.0, 1.0, 1.0, 0), (7, 3, 3, 1.0, 4.0, 1.0, 1)
2114
], dtype=order_dt)
2115
)
2116
record_arrays_close(
2117
from_signals_shortonly(size=1, fixed_fees=[[-0.1, 0., 0.1, 1.]]).order_records,
2118
np.array([
2119
(0, 0, 0, 1.0, 1.0, -0.1, 1), (1, 0, 3, 1.0, 4.0, -0.1, 0), (2, 1, 0, 1.0, 1.0, 0.0, 1),
2120
(3, 1, 3, 1.0, 4.0, 0.0, 0), (4, 2, 0, 1.0, 1.0, 0.1, 1), (5, 2, 3, 1.0, 4.0, 0.1, 0),
2121
(6, 3, 0, 1.0, 1.0, 1.0, 1), (7, 3, 3, 1.0, 4.0, 1.0, 0)
2122
], dtype=order_dt)
2123
)
2124
2125
def test_slippage(self):
2126
record_arrays_close(
2127
from_signals_both(size=1, slippage=[[0., 0.1, 1.]]).order_records,
2128
np.array([
2129
(0, 0, 0, 1.0, 1.0, 0.0, 0), (1, 0, 3, 2.0, 4.0, 0.0, 1), (2, 1, 0, 1.0, 1.1, 0.0, 0),
2130
(3, 1, 3, 2.0, 3.6, 0.0, 1), (4, 2, 0, 1.0, 2.0, 0.0, 0), (5, 2, 3, 2.0, 0.0, 0.0, 1)
2131
], dtype=order_dt)
2132
)
2133
record_arrays_close(
2134
from_signals_longonly(size=1, slippage=[[0., 0.1, 1.]]).order_records,
2135
np.array([
2136
(0, 0, 0, 1.0, 1.0, 0.0, 0), (1, 0, 3, 1.0, 4.0, 0.0, 1), (2, 1, 0, 1.0, 1.1, 0.0, 0),
2137
(3, 1, 3, 1.0, 3.6, 0.0, 1), (4, 2, 0, 1.0, 2.0, 0.0, 0), (5, 2, 3, 1.0, 0.0, 0.0, 1)
2138
], dtype=order_dt)
2139
)
2140
record_arrays_close(
2141
from_signals_shortonly(size=1, slippage=[[0., 0.1, 1.]]).order_records,
2142
np.array([
2143
(0, 0, 0, 1.0, 1.0, 0.0, 1), (1, 0, 3, 1.0, 4.0, 0.0, 0), (2, 1, 0, 1.0, 0.9, 0.0, 1),
2144
(3, 1, 3, 1.0, 4.4, 0.0, 0), (4, 2, 0, 1.0, 0.0, 0.0, 1), (5, 2, 3, 1.0, 8.0, 0.0, 0)
2145
], dtype=order_dt)
2146
)
2147
2148
def test_min_size(self):
2149
record_arrays_close(
2150
from_signals_both(size=1, min_size=[[0., 1., 2.]]).order_records,
2151
np.array([
2152
(0, 0, 0, 1.0, 1.0, 0.0, 0), (1, 0, 3, 2.0, 4.0, 0.0, 1), (2, 1, 0, 1.0, 1.0, 0.0, 0),
2153
(3, 1, 3, 2.0, 4.0, 0.0, 1)
2154
], dtype=order_dt)
2155
)
2156
record_arrays_close(
2157
from_signals_longonly(size=1, min_size=[[0., 1., 2.]]).order_records,
2158
np.array([
2159
(0, 0, 0, 1.0, 1.0, 0.0, 0), (1, 0, 3, 1.0, 4.0, 0.0, 1), (2, 1, 0, 1.0, 1.0, 0.0, 0),
2160
(3, 1, 3, 1.0, 4.0, 0.0, 1)
2161
], dtype=order_dt)
2162
)
2163
record_arrays_close(
2164
from_signals_shortonly(size=1, min_size=[[0., 1., 2.]]).order_records,
2165
np.array([
2166
(0, 0, 0, 1.0, 1.0, 0.0, 1), (1, 0, 3, 1.0, 4.0, 0.0, 0), (2, 1, 0, 1.0, 1.0, 0.0, 1),
2167
(3, 1, 3, 1.0, 4.0, 0.0, 0)
2168
], dtype=order_dt)
2169
)
2170
2171
def test_max_size(self):
2172
record_arrays_close(
2173
from_signals_both(size=1, max_size=[[0.5, 1., np.inf]]).order_records,
2174
np.array([
2175
(0, 0, 0, 0.5, 1.0, 0.0, 0), (1, 0, 3, 0.5, 4.0, 0.0, 1), (2, 0, 4, 0.5, 5.0, 0.0, 1),
2176
(3, 1, 0, 1.0, 1.0, 0.0, 0), (4, 1, 3, 1.0, 4.0, 0.0, 1), (5, 1, 4, 1.0, 5.0, 0.0, 1),
2177
(6, 2, 0, 1.0, 1.0, 0.0, 0), (7, 2, 3, 2.0, 4.0, 0.0, 1)
2178
], dtype=order_dt)
2179
)
2180
record_arrays_close(
2181
from_signals_longonly(size=1, max_size=[[0.5, 1., np.inf]]).order_records,
2182
np.array([
2183
(0, 0, 0, 0.5, 1.0, 0.0, 0), (1, 0, 3, 0.5, 4.0, 0.0, 1), (2, 1, 0, 1.0, 1.0, 0.0, 0),
2184
(3, 1, 3, 1.0, 4.0, 0.0, 1), (4, 2, 0, 1.0, 1.0, 0.0, 0), (5, 2, 3, 1.0, 4.0, 0.0, 1)
2185
], dtype=order_dt)
2186
)
2187
record_arrays_close(
2188
from_signals_shortonly(size=1, max_size=[[0.5, 1., np.inf]]).order_records,
2189
np.array([
2190
(0, 0, 0, 0.5, 1.0, 0.0, 1), (1, 0, 3, 0.5, 4.0, 0.0, 0), (2, 1, 0, 1.0, 1.0, 0.0, 1),
2191
(3, 1, 3, 1.0, 4.0, 0.0, 0), (4, 2, 0, 1.0, 1.0, 0.0, 1), (5, 2, 3, 1.0, 4.0, 0.0, 0)
2192
], dtype=order_dt)
2193
)
2194
2195
def test_reject_prob(self):
2196
record_arrays_close(
2197
from_signals_both(size=1., reject_prob=[[0., 0.5, 1.]], seed=42).order_records,
2198
np.array([
2199
(0, 0, 0, 1.0, 1.0, 0.0, 0), (1, 0, 3, 2.0, 4.0, 0.0, 1), (2, 1, 1, 1.0, 2.0, 0.0, 0),
2200
(3, 1, 3, 2.0, 4.0, 0.0, 1)
2201
], dtype=order_dt)
2202
)
2203
record_arrays_close(
2204
from_signals_longonly(size=1., reject_prob=[[0., 0.5, 1.]], seed=42).order_records,
2205
np.array([
2206
(0, 0, 0, 1.0, 1.0, 0.0, 0), (1, 0, 3, 1.0, 4.0, 0.0, 1), (2, 1, 1, 1.0, 2.0, 0.0, 0),
2207
(3, 1, 3, 1.0, 4.0, 0.0, 1)
2208
], dtype=order_dt)
2209
)
2210
record_arrays_close(
2211
from_signals_shortonly(size=1., reject_prob=[[0., 0.5, 1.]], seed=42).order_records,
2212
np.array([
2213
(0, 0, 0, 1.0, 1.0, 0.0, 1), (1, 0, 3, 1.0, 4.0, 0.0, 0), (2, 1, 1, 1.0, 2.0, 0.0, 1),
2214
(3, 1, 3, 1.0, 4.0, 0.0, 0)
2215
], dtype=order_dt)
2216
)
2217
2218
def test_allow_partial(self):
2219
record_arrays_close(
2220
from_signals_both(size=1000, allow_partial=[[True, False]]).order_records,
2221
np.array([
2222
(0, 0, 0, 100.0, 1.0, 0.0, 0), (1, 0, 3, 1100.0, 4.0, 0.0, 1), (2, 1, 3, 1000.0, 4.0, 0.0, 1)
2223
], dtype=order_dt)
2224
)
2225
record_arrays_close(
2226
from_signals_longonly(size=1000, allow_partial=[[True, False]]).order_records,
2227
np.array([
2228
(0, 0, 0, 100.0, 1.0, 0.0, 0), (1, 0, 3, 100.0, 4.0, 0.0, 1)
2229
], dtype=order_dt)
2230
)
2231
record_arrays_close(
2232
from_signals_shortonly(size=1000, allow_partial=[[True, False]]).order_records,
2233
np.array([
2234
(0, 0, 0, 1000.0, 1.0, 0.0, 1), (1, 0, 3, 275.0, 4.0, 0.0, 0), (2, 1, 0, 1000.0, 1.0, 0.0, 1)
2235
], dtype=order_dt)
2236
)
2237
record_arrays_close(
2238
from_signals_both(size=np.inf, allow_partial=[[True, False]]).order_records,
2239
np.array([
2240
(0, 0, 0, 100.0, 1.0, 0.0, 0), (1, 0, 3, 200.0, 4.0, 0.0, 1), (2, 1, 0, 100.0, 1.0, 0.0, 0),
2241
(3, 1, 3, 200.0, 4.0, 0.0, 1)
2242
], dtype=order_dt)
2243
)
2244
record_arrays_close(
2245
from_signals_longonly(size=np.inf, allow_partial=[[True, False]]).order_records,
2246
np.array([
2247
(0, 0, 0, 100.0, 1.0, 0.0, 0), (1, 0, 3, 100.0, 4.0, 0.0, 1), (2, 1, 0, 100.0, 1.0, 0.0, 0),
2248
(3, 1, 3, 100.0, 4.0, 0.0, 1)
2249
], dtype=order_dt)
2250
)
2251
record_arrays_close(
2252
from_signals_shortonly(size=np.inf, allow_partial=[[True, False]]).order_records,
2253
np.array([
2254
(0, 0, 0, 100.0, 1.0, 0.0, 1), (1, 0, 3, 50.0, 4.0, 0.0, 0), (2, 1, 0, 100.0, 1.0, 0.0, 1)
2255
], dtype=order_dt)
2256
)
2257
2258
def test_raise_reject(self):
2259
record_arrays_close(
2260
from_signals_both(size=1000, allow_partial=True, raise_reject=True).order_records,
2261
np.array([
2262
(0, 0, 0, 100.0, 1.0, 0.0, 0), (1, 0, 3, 1100.0, 4.0, 0.0, 1)
2263
], dtype=order_dt)
2264
)
2265
record_arrays_close(
2266
from_signals_longonly(size=1000, allow_partial=True, raise_reject=True).order_records,
2267
np.array([
2268
(0, 0, 0, 100.0, 1.0, 0.0, 0), (1, 0, 3, 100.0, 4.0, 0.0, 1)
2269
], dtype=order_dt)
2270
)
2271
with pytest.raises(Exception):
2272
_ = from_signals_shortonly(size=1000, allow_partial=True, raise_reject=True).order_records
2273
with pytest.raises(Exception):
2274
_ = from_signals_both(size=1000, allow_partial=False, raise_reject=True).order_records
2275
with pytest.raises(Exception):
2276
_ = from_signals_longonly(size=1000, allow_partial=False, raise_reject=True).order_records
2277
with pytest.raises(Exception):
2278
_ = from_signals_shortonly(size=1000, allow_partial=False, raise_reject=True).order_records
2279
2280
def test_log(self):
2281
record_arrays_close(
2282
from_signals_both(log=True).log_records,
2283
np.array([
2284
(0, 0, 0, 0, 100.0, 0.0, 0.0, 100.0, 1.0, 100.0, np.inf, 1.0, 0, 2, 0.0, 0.0,
2285
0.0, 1e-08, np.inf, np.nan, 0.0, False, True, False, True, 0.0, 100.0, 0.0, 0.0, 1.0,
2286
100.0, 100.0, 1.0, 0.0, 0, 0, -1, 0),
2287
(1, 0, 0, 3, 0.0, 100.0, 0.0, 0.0, 4.0, 400.0, -np.inf, 4.0, 0, 2, 0.0,
2288
0.0, 0.0, 1e-08, np.inf, np.nan, 0.0, False, True, False, True, 800.0, -100.0,
2289
400.0, 0.0, 4.0, 400.0, 200.0, 4.0, 0.0, 1, 0, -1, 1)
2290
], dtype=log_dt)
2291
)
2292
2293
def test_accumulate(self):
2294
record_arrays_close(
2295
from_signals_both(size=1, accumulate=[['disabled', 'addonly', 'removeonly', 'both']]).order_records,
2296
np.array([
2297
(0, 0, 0, 1.0, 1.0, 0.0, 0), (1, 0, 3, 2.0, 4.0, 0.0, 1), (2, 1, 0, 1.0, 1.0, 0.0, 0),
2298
(3, 1, 1, 1.0, 2.0, 0.0, 0), (4, 1, 3, 3.0, 4.0, 0.0, 1), (5, 1, 4, 1.0, 5.0, 0.0, 1),
2299
(6, 2, 0, 1.0, 1.0, 0.0, 0), (7, 2, 3, 1.0, 4.0, 0.0, 1), (8, 2, 4, 1.0, 5.0, 0.0, 1),
2300
(9, 3, 0, 1.0, 1.0, 0.0, 0), (10, 3, 1, 1.0, 2.0, 0.0, 0), (11, 3, 3, 1.0, 4.0, 0.0, 1),
2301
(12, 3, 4, 1.0, 5.0, 0.0, 1)
2302
], dtype=order_dt)
2303
)
2304
record_arrays_close(
2305
from_signals_longonly(size=1, accumulate=[['disabled', 'addonly', 'removeonly', 'both']]).order_records,
2306
np.array([
2307
(0, 0, 0, 1.0, 1.0, 0.0, 0), (1, 0, 3, 1.0, 4.0, 0.0, 1), (2, 1, 0, 1.0, 1.0, 0.0, 0),
2308
(3, 1, 1, 1.0, 2.0, 0.0, 0), (4, 1, 3, 2.0, 4.0, 0.0, 1), (5, 2, 0, 1.0, 1.0, 0.0, 0),
2309
(6, 2, 3, 1.0, 4.0, 0.0, 1), (7, 3, 0, 1.0, 1.0, 0.0, 0), (8, 3, 1, 1.0, 2.0, 0.0, 0),
2310
(9, 3, 3, 1.0, 4.0, 0.0, 1), (10, 3, 4, 1.0, 5.0, 0.0, 1)
2311
], dtype=order_dt)
2312
)
2313
record_arrays_close(
2314
from_signals_shortonly(size=1, accumulate=[['disabled', 'addonly', 'removeonly', 'both']]).order_records,
2315
np.array([
2316
(0, 0, 0, 1.0, 1.0, 0.0, 1), (1, 0, 3, 1.0, 4.0, 0.0, 0), (2, 1, 0, 1.0, 1.0, 0.0, 1),
2317
(3, 1, 1, 1.0, 2.0, 0.0, 1), (4, 1, 3, 2.0, 4.0, 0.0, 0), (5, 2, 0, 1.0, 1.0, 0.0, 1),
2318
(6, 2, 3, 1.0, 4.0, 0.0, 0), (7, 3, 0, 1.0, 1.0, 0.0, 1), (8, 3, 1, 1.0, 2.0, 0.0, 1),
2319
(9, 3, 3, 1.0, 4.0, 0.0, 0), (10, 3, 4, 1.0, 5.0, 0.0, 0)
2320
], dtype=order_dt)
2321
)
2322
2323
def test_upon_long_conflict(self):
2324
kwargs = dict(
2325
close=price[:3],
2326
entries=pd.DataFrame([
2327
[True, True, True, True, True, True, True],
2328
[True, True, True, True, False, True, False],
2329
[True, True, True, True, True, True, True]
2330
]),
2331
exits=pd.DataFrame([
2332
[True, True, True, True, True, True, True],
2333
[False, False, False, False, True, False, True],
2334
[True, True, True, True, True, True, True]
2335
]),
2336
size=1.,
2337
accumulate=True,
2338
upon_long_conflict=[[
2339
'ignore',
2340
'entry',
2341
'exit',
2342
'adjacent',
2343
'adjacent',
2344
'opposite',
2345
'opposite'
2346
]]
2347
)
2348
record_arrays_close(
2349
from_signals_longonly(**kwargs).order_records,
2350
np.array([
2351
(0, 0, 1, 1.0, 2.0, 0.0, 0),
2352
(1, 1, 0, 1.0, 1.0, 0.0, 0), (2, 1, 1, 1.0, 2.0, 0.0, 0), (3, 1, 2, 1.0, 3.0, 0.0, 0),
2353
(4, 2, 1, 1.0, 2.0, 0.0, 0), (5, 2, 2, 1.0, 3.0, 0.0, 1),
2354
(6, 3, 1, 1.0, 2.0, 0.0, 0), (7, 3, 2, 1.0, 3.0, 0.0, 0),
2355
(8, 5, 1, 1.0, 2.0, 0.0, 0), (9, 5, 2, 1.0, 3.0, 0.0, 1)
2356
], dtype=order_dt)
2357
)
2358
2359
def test_upon_short_conflict(self):
2360
kwargs = dict(
2361
close=price[:3],
2362
entries=pd.DataFrame([
2363
[True, True, True, True, True, True, True],
2364
[True, True, True, True, False, True, False],
2365
[True, True, True, True, True, True, True]
2366
]),
2367
exits=pd.DataFrame([
2368
[True, True, True, True, True, True, True],
2369
[False, False, False, False, True, False, True],
2370
[True, True, True, True, True, True, True]
2371
]),
2372
size=1.,
2373
accumulate=True,
2374
upon_short_conflict=[[
2375
'ignore',
2376
'entry',
2377
'exit',
2378
'adjacent',
2379
'adjacent',
2380
'opposite',
2381
'opposite'
2382
]]
2383
)
2384
record_arrays_close(
2385
from_signals_shortonly(**kwargs).order_records,
2386
np.array([
2387
(0, 0, 1, 1.0, 2.0, 0.0, 1),
2388
(1, 1, 0, 1.0, 1.0, 0.0, 1), (2, 1, 1, 1.0, 2.0, 0.0, 1), (3, 1, 2, 1.0, 3.0, 0.0, 1),
2389
(4, 2, 1, 1.0, 2.0, 0.0, 1), (5, 2, 2, 1.0, 3.0, 0.0, 0),
2390
(6, 3, 1, 1.0, 2.0, 0.0, 1), (7, 3, 2, 1.0, 3.0, 0.0, 1),
2391
(8, 5, 1, 1.0, 2.0, 0.0, 1), (9, 5, 2, 1.0, 3.0, 0.0, 0)
2392
], dtype=order_dt)
2393
)
2394
2395
def test_upon_dir_conflict(self):
2396
kwargs = dict(
2397
close=price[:3],
2398
entries=pd.DataFrame([
2399
[True, True, True, True, True, True, True],
2400
[True, True, True, True, False, True, False],
2401
[True, True, True, True, True, True, True]
2402
]),
2403
exits=pd.DataFrame([
2404
[True, True, True, True, True, True, True],
2405
[False, False, False, False, True, False, True],
2406
[True, True, True, True, True, True, True]
2407
]),
2408
size=1.,
2409
accumulate=True,
2410
upon_dir_conflict=[[
2411
'ignore',
2412
'long',
2413
'short',
2414
'adjacent',
2415
'adjacent',
2416
'opposite',
2417
'opposite'
2418
]]
2419
)
2420
record_arrays_close(
2421
from_signals_both(**kwargs).order_records,
2422
np.array([
2423
(0, 0, 1, 1.0, 2.0, 0.0, 0),
2424
(1, 1, 0, 1.0, 1.0, 0.0, 0), (2, 1, 1, 1.0, 2.0, 0.0, 0), (3, 1, 2, 1.0, 3.0, 0.0, 0),
2425
(4, 2, 0, 1.0, 1.0, 0.0, 1), (5, 2, 1, 1.0, 2.0, 0.0, 0), (6, 2, 2, 1.0, 3.0, 0.0, 1),
2426
(7, 3, 1, 1.0, 2.0, 0.0, 0), (8, 3, 2, 1.0, 3.0, 0.0, 0),
2427
(9, 4, 1, 1.0, 2.0, 0.0, 1), (10, 4, 2, 1.0, 3.0, 0.0, 1),
2428
(11, 5, 1, 1.0, 2.0, 0.0, 0), (12, 5, 2, 1.0, 3.0, 0.0, 1),
2429
(13, 6, 1, 1.0, 2.0, 0.0, 1), (14, 6, 2, 1.0, 3.0, 0.0, 0)
2430
], dtype=order_dt)
2431
)
2432
2433
def test_upon_opposite_entry(self):
2434
kwargs = dict(
2435
close=price[:3],
2436
entries=pd.DataFrame([
2437
[True, False, True, False, True, False, True, False, True, False],
2438
[False, True, False, True, False, True, False, True, False, True],
2439
[True, False, True, False, True, False, True, False, True, False]
2440
]),
2441
exits=pd.DataFrame([
2442
[False, True, False, True, False, True, False, True, False, True],
2443
[True, False, True, False, True, False, True, False, True, False],
2444
[False, True, False, True, False, True, False, True, False, True]
2445
]),
2446
size=1.,
2447
upon_opposite_entry=[[
2448
'ignore',
2449
'ignore',
2450
'close',
2451
'close',
2452
'closereduce',
2453
'closereduce',
2454
'reverse',
2455
'reverse',
2456
'reversereduce',
2457
'reversereduce'
2458
]]
2459
)
2460
record_arrays_close(
2461
from_signals_both(**kwargs).order_records,
2462
np.array([
2463
(0, 0, 0, 1.0, 1.0, 0.0, 0),
2464
(1, 1, 0, 1.0, 1.0, 0.0, 1),
2465
(2, 2, 0, 1.0, 1.0, 0.0, 0), (3, 2, 1, 1.0, 2.0, 0.0, 1), (4, 2, 2, 1.0, 3.0, 0.0, 0),
2466
(5, 3, 0, 1.0, 1.0, 0.0, 1), (6, 3, 1, 1.0, 2.0, 0.0, 0), (7, 3, 2, 1.0, 3.0, 0.0, 1),
2467
(8, 4, 0, 1.0, 1.0, 0.0, 0), (9, 4, 1, 1.0, 2.0, 0.0, 1), (10, 4, 2, 1.0, 3.0, 0.0, 0),
2468
(11, 5, 0, 1.0, 1.0, 0.0, 1), (12, 5, 1, 1.0, 2.0, 0.0, 0), (13, 5, 2, 1.0, 3.0, 0.0, 1),
2469
(14, 6, 0, 1.0, 1.0, 0.0, 0), (15, 6, 1, 2.0, 2.0, 0.0, 1), (16, 6, 2, 2.0, 3.0, 0.0, 0),
2470
(17, 7, 0, 1.0, 1.0, 0.0, 1), (18, 7, 1, 2.0, 2.0, 0.0, 0), (19, 7, 2, 2.0, 3.0, 0.0, 1),
2471
(20, 8, 0, 1.0, 1.0, 0.0, 0), (21, 8, 1, 2.0, 2.0, 0.0, 1), (22, 8, 2, 2.0, 3.0, 0.0, 0),
2472
(23, 9, 0, 1.0, 1.0, 0.0, 1), (24, 9, 1, 2.0, 2.0, 0.0, 0), (25, 9, 2, 2.0, 3.0, 0.0, 1)
2473
], dtype=order_dt)
2474
)
2475
record_arrays_close(
2476
from_signals_both(**kwargs, accumulate=True).order_records,
2477
np.array([
2478
(0, 0, 0, 1.0, 1.0, 0.0, 0), (1, 0, 2, 1.0, 3.0, 0.0, 0),
2479
(2, 1, 0, 1.0, 1.0, 0.0, 1), (3, 1, 2, 1.0, 3.0, 0.0, 1),
2480
(4, 2, 0, 1.0, 1.0, 0.0, 0), (5, 2, 1, 1.0, 2.0, 0.0, 1), (6, 2, 2, 1.0, 3.0, 0.0, 0),
2481
(7, 3, 0, 1.0, 1.0, 0.0, 1), (8, 3, 1, 1.0, 2.0, 0.0, 0), (9, 3, 2, 1.0, 3.0, 0.0, 1),
2482
(10, 4, 0, 1.0, 1.0, 0.0, 0), (11, 4, 1, 1.0, 2.0, 0.0, 1), (12, 4, 2, 1.0, 3.0, 0.0, 0),
2483
(13, 5, 0, 1.0, 1.0, 0.0, 1), (14, 5, 1, 1.0, 2.0, 0.0, 0), (15, 5, 2, 1.0, 3.0, 0.0, 1),
2484
(16, 6, 0, 1.0, 1.0, 0.0, 0), (17, 6, 1, 2.0, 2.0, 0.0, 1), (18, 6, 2, 2.0, 3.0, 0.0, 0),
2485
(19, 7, 0, 1.0, 1.0, 0.0, 1), (20, 7, 1, 2.0, 2.0, 0.0, 0), (21, 7, 2, 2.0, 3.0, 0.0, 1),
2486
(22, 8, 0, 1.0, 1.0, 0.0, 0), (23, 8, 1, 1.0, 2.0, 0.0, 1), (24, 8, 2, 1.0, 3.0, 0.0, 0),
2487
(25, 9, 0, 1.0, 1.0, 0.0, 1), (26, 9, 1, 1.0, 2.0, 0.0, 0), (27, 9, 2, 1.0, 3.0, 0.0, 1)
2488
], dtype=order_dt)
2489
)
2490
2491
def test_init_cash(self):
2492
record_arrays_close(
2493
from_signals_both(close=price_wide, size=1., init_cash=[0., 1., 100.]).order_records,
2494
np.array([
2495
(0, 0, 3, 1.0, 4.0, 0.0, 1), (1, 1, 0, 1.0, 1.0, 0.0, 0), (2, 1, 3, 2.0, 4.0, 0.0, 1),
2496
(3, 2, 0, 1.0, 1.0, 0.0, 0), (4, 2, 3, 2.0, 4.0, 0.0, 1)
2497
], dtype=order_dt)
2498
)
2499
record_arrays_close(
2500
from_signals_longonly(close=price_wide, size=1., init_cash=[0., 1., 100.]).order_records,
2501
np.array([
2502
(0, 1, 0, 1.0, 1.0, 0.0, 0), (1, 1, 3, 1.0, 4.0, 0.0, 1), (2, 2, 0, 1.0, 1.0, 0.0, 0),
2503
(3, 2, 3, 1.0, 4.0, 0.0, 1)
2504
], dtype=order_dt)
2505
)
2506
record_arrays_close(
2507
from_signals_shortonly(close=price_wide, size=1., init_cash=[0., 1., 100.]).order_records,
2508
np.array([
2509
(0, 0, 0, 1.0, 1.0, 0.0, 1), (1, 0, 3, 0.25, 4.0, 0.0, 0), (2, 1, 0, 1.0, 1.0, 0.0, 1),
2510
(3, 1, 3, 0.5, 4.0, 0.0, 0), (4, 2, 0, 1.0, 1.0, 0.0, 1), (5, 2, 3, 1.0, 4.0, 0.0, 0)
2511
], dtype=order_dt)
2512
)
2513
with pytest.raises(Exception):
2514
_ = from_signals_both(init_cash=np.inf).order_records
2515
with pytest.raises(Exception):
2516
_ = from_signals_longonly(init_cash=np.inf).order_records
2517
with pytest.raises(Exception):
2518
_ = from_signals_shortonly(init_cash=np.inf).order_records
2519
2520
def test_group_by(self):
2521
pf = from_signals_both(close=price_wide, group_by=np.array([0, 0, 1]))
2522
record_arrays_close(
2523
pf.order_records,
2524
np.array([
2525
(0, 0, 0, 100.0, 1.0, 0.0, 0), (1, 0, 3, 200.0, 4.0, 0.0, 1), (2, 1, 0, 100.0, 1.0, 0.0, 0),
2526
(3, 1, 3, 200.0, 4.0, 0.0, 1), (4, 2, 0, 100.0, 1.0, 0.0, 0), (5, 2, 3, 200.0, 4.0, 0.0, 1)
2527
], dtype=order_dt)
2528
)
2529
pd.testing.assert_index_equal(
2530
pf.wrapper.grouper.group_by,
2531
pd.Index([0, 0, 1], dtype='int64')
2532
)
2533
pd.testing.assert_series_equal(
2534
pf.init_cash,
2535
pd.Series([200., 100.], index=pd.Index([0, 1], dtype='int64')).rename('init_cash')
2536
)
2537
assert not pf.cash_sharing
2538
2539
def test_cash_sharing(self):
2540
pf = from_signals_both(close=price_wide, group_by=np.array([0, 0, 1]), cash_sharing=True)
2541
record_arrays_close(
2542
pf.order_records,
2543
np.array([
2544
(0, 0, 0, 100., 1., 0., 0), (1, 0, 3, 200., 4., 0., 1),
2545
(2, 2, 0, 100., 1., 0., 0), (3, 2, 3, 200., 4., 0., 1)
2546
], dtype=order_dt)
2547
)
2548
pd.testing.assert_index_equal(
2549
pf.wrapper.grouper.group_by,
2550
pd.Index([0, 0, 1], dtype='int64')
2551
)
2552
pd.testing.assert_series_equal(
2553
pf.init_cash,
2554
pd.Series([100., 100.], index=pd.Index([0, 1], dtype='int64')).rename('init_cash')
2555
)
2556
assert pf.cash_sharing
2557
with pytest.raises(Exception):
2558
_ = pf.regroup(group_by=False)
2559
2560
def test_call_seq(self):
2561
pf = from_signals_both(close=price_wide, group_by=np.array([0, 0, 1]), cash_sharing=True)
2562
record_arrays_close(
2563
pf.order_records,
2564
np.array([
2565
(0, 0, 0, 100., 1., 0., 0), (1, 0, 3, 200., 4., 0., 1),
2566
(2, 2, 0, 100., 1., 0., 0), (3, 2, 3, 200., 4., 0., 1)
2567
], dtype=order_dt)
2568
)
2569
np.testing.assert_array_equal(
2570
pf.call_seq.values,
2571
np.array([
2572
[0, 1, 0],
2573
[0, 1, 0],
2574
[0, 1, 0],
2575
[0, 1, 0],
2576
[0, 1, 0]
2577
])
2578
)
2579
pf = from_signals_both(
2580
close=price_wide, group_by=np.array([0, 0, 1]),
2581
cash_sharing=True, call_seq='reversed')
2582
record_arrays_close(
2583
pf.order_records,
2584
np.array([
2585
(0, 1, 0, 100., 1., 0., 0), (1, 1, 3, 200., 4., 0., 1),
2586
(2, 2, 0, 100., 1., 0., 0), (3, 2, 3, 200., 4., 0., 1)
2587
], dtype=order_dt)
2588
)
2589
np.testing.assert_array_equal(
2590
pf.call_seq.values,
2591
np.array([
2592
[1, 0, 0],
2593
[1, 0, 0],
2594
[1, 0, 0],
2595
[1, 0, 0],
2596
[1, 0, 0]
2597
])
2598
)
2599
pf = from_signals_both(
2600
close=price_wide, group_by=np.array([0, 0, 1]),
2601
cash_sharing=True, call_seq='random', seed=seed)
2602
record_arrays_close(
2603
pf.order_records,
2604
np.array([
2605
(0, 1, 0, 100., 1., 0., 0), (1, 1, 3, 200., 4., 0., 1),
2606
(2, 2, 0, 100., 1., 0., 0), (3, 2, 3, 200., 4., 0., 1)
2607
], dtype=order_dt)
2608
)
2609
np.testing.assert_array_equal(
2610
pf.call_seq.values,
2611
np.array([
2612
[1, 0, 0],
2613
[0, 1, 0],
2614
[1, 0, 0],
2615
[1, 0, 0],
2616
[1, 0, 0]
2617
])
2618
)
2619
kwargs = dict(
2620
close=1.,
2621
entries=pd.DataFrame([
2622
[False, False, True],
2623
[False, True, False],
2624
[True, False, False],
2625
[False, False, True],
2626
[False, True, False],
2627
]),
2628
exits=pd.DataFrame([
2629
[False, False, False],
2630
[False, False, True],
2631
[False, True, False],
2632
[True, False, False],
2633
[False, False, True],
2634
]),
2635
group_by=np.array([0, 0, 0]),
2636
cash_sharing=True,
2637
call_seq='auto'
2638
)
2639
pf = from_signals_both(**kwargs)
2640
record_arrays_close(
2641
pf.order_records,
2642
np.array([
2643
(0, 2, 0, 100., 1., 0., 0), (1, 2, 1, 200., 1., 0., 1),
2644
(2, 1, 1, 200., 1., 0., 0), (3, 1, 2, 200., 1., 0., 1),
2645
(4, 0, 2, 200., 1., 0., 0), (5, 0, 3, 200., 1., 0., 1),
2646
(6, 2, 3, 200., 1., 0., 0), (7, 2, 4, 200., 1., 0., 1),
2647
(8, 1, 4, 200., 1., 0., 0)
2648
], dtype=order_dt)
2649
)
2650
np.testing.assert_array_equal(
2651
pf.call_seq.values,
2652
np.array([
2653
[0, 1, 2],
2654
[2, 0, 1],
2655
[1, 2, 0],
2656
[0, 1, 2],
2657
[2, 0, 1]
2658
])
2659
)
2660
pf = from_signals_longonly(**kwargs)
2661
record_arrays_close(
2662
pf.order_records,
2663
np.array([
2664
(0, 2, 0, 100., 1., 0., 0), (1, 2, 1, 100., 1., 0., 1),
2665
(2, 1, 1, 100., 1., 0., 0), (3, 1, 2, 100., 1., 0., 1),
2666
(4, 0, 2, 100., 1., 0., 0), (5, 0, 3, 100., 1., 0., 1),
2667
(6, 2, 3, 100., 1., 0., 0), (7, 2, 4, 100., 1., 0., 1),
2668
(8, 1, 4, 100., 1., 0., 0)
2669
], dtype=order_dt)
2670
)
2671
np.testing.assert_array_equal(
2672
pf.call_seq.values,
2673
np.array([
2674
[0, 1, 2],
2675
[2, 0, 1],
2676
[1, 2, 0],
2677
[0, 1, 2],
2678
[2, 0, 1]
2679
])
2680
)
2681
pf = from_signals_shortonly(**kwargs)
2682
record_arrays_close(
2683
pf.order_records,
2684
np.array([
2685
(0, 2, 0, 100., 1., 0., 1), (1, 2, 1, 100., 1., 0., 0),
2686
(2, 0, 2, 100., 1., 0., 1), (3, 0, 3, 100., 1., 0., 0),
2687
(4, 1, 4, 100., 1., 0., 1)
2688
], dtype=order_dt)
2689
)
2690
np.testing.assert_array_equal(
2691
pf.call_seq.values,
2692
np.array([
2693
[2, 0, 1],
2694
[1, 0, 2],
2695
[0, 1, 2],
2696
[2, 1, 0],
2697
[1, 0, 2]
2698
])
2699
)
2700
pf = from_signals_longonly(**kwargs, size=1., size_type='percent')
2701
record_arrays_close(
2702
pf.order_records,
2703
np.array([
2704
(0, 2, 0, 100.0, 1.0, 0.0, 0), (1, 2, 1, 100.0, 1.0, 0.0, 1), (2, 1, 1, 100.0, 1.0, 0.0, 0),
2705
(3, 1, 2, 100.0, 1.0, 0.0, 1), (4, 0, 2, 100.0, 1.0, 0.0, 0), (5, 0, 3, 100.0, 1.0, 0.0, 1),
2706
(6, 2, 3, 100.0, 1.0, 0.0, 0), (7, 2, 4, 100.0, 1.0, 0.0, 1), (8, 1, 4, 100.0, 1.0, 0.0, 0)
2707
], dtype=order_dt)
2708
)
2709
np.testing.assert_array_equal(
2710
pf.call_seq.values,
2711
np.array([
2712
[0, 1, 2],
2713
[2, 0, 1],
2714
[1, 0, 2],
2715
[0, 1, 2],
2716
[2, 0, 1]
2717
])
2718
)
2719
2720
def test_sl_stop(self):
2721
entries = pd.Series([True, False, False, False, False], index=price.index)
2722
exits = pd.Series([False, False, False, False, False], index=price.index)
2723
2724
with pytest.raises(Exception):
2725
_ = from_signals_both(sl_stop=-0.1)
2726
2727
close = pd.Series([5., 4., 3., 2., 1.], index=price.index)
2728
open = close + 0.25
2729
high = close + 0.5
2730
low = close - 0.5
2731
record_arrays_close(
2732
from_signals_longonly(
2733
close=close, entries=entries, exits=exits,
2734
sl_stop=[[np.nan, 0.1, 0.5, np.inf]]).order_records,
2735
np.array([
2736
(0, 0, 0, 20.0, 5.0, 0.0, 0),
2737
(1, 1, 0, 20.0, 5.0, 0.0, 0), (2, 1, 1, 20.0, 4.0, 0.0, 1),
2738
(3, 2, 0, 20.0, 5.0, 0.0, 0), (4, 2, 3, 20.0, 2.0, 0.0, 1),
2739
(5, 3, 0, 20.0, 5.0, 0.0, 0)
2740
], dtype=order_dt)
2741
)
2742
record_arrays_close(
2743
from_signals_shortonly(
2744
close=close, entries=entries, exits=exits,
2745
sl_stop=[[np.nan, 0.1, 0.5, np.inf]]).order_records,
2746
np.array([
2747
(0, 0, 0, 20.0, 5.0, 0.0, 1),
2748
(1, 1, 0, 20.0, 5.0, 0.0, 1),
2749
(2, 2, 0, 20.0, 5.0, 0.0, 1),
2750
(3, 3, 0, 20.0, 5.0, 0.0, 1)
2751
], dtype=order_dt)
2752
)
2753
record_arrays_close(
2754
from_signals_both(
2755
close=close, entries=entries, exits=exits,
2756
sl_stop=[[np.nan, 0.1, 0.5, np.inf]]).order_records,
2757
from_signals_longonly(
2758
close=close, entries=entries, exits=exits,
2759
sl_stop=[[np.nan, 0.1, 0.5, np.inf]]).order_records
2760
)
2761
record_arrays_close(
2762
from_signals_both(
2763
close=close, entries=exits, exits=entries,
2764
sl_stop=[[np.nan, 0.1, 0.5, np.inf]]).order_records,
2765
from_signals_shortonly(
2766
close=close, entries=entries, exits=exits,
2767
sl_stop=[[np.nan, 0.1, 0.5, np.inf]]).order_records
2768
)
2769
record_arrays_close(
2770
from_signals_longonly(
2771
close=close, entries=entries, exits=exits,
2772
open=open, high=high, low=low,
2773
sl_stop=[[np.nan, 0.1, 0.15, 0.2, np.inf]]).order_records,
2774
np.array([
2775
(0, 0, 0, 20.0, 5.0, 0.0, 0),
2776
(1, 1, 0, 20.0, 5.0, 0.0, 0), (2, 1, 1, 20.0, 4.25, 0.0, 1),
2777
(3, 2, 0, 20.0, 5.0, 0.0, 0), (4, 2, 1, 20.0, 4.25, 0.0, 1),
2778
(5, 3, 0, 20.0, 5.0, 0.0, 0), (6, 3, 1, 20.0, 4.0, 0.0, 1),
2779
(7, 4, 0, 20.0, 5.0, 0.0, 0)
2780
], dtype=order_dt)
2781
)
2782
record_arrays_close(
2783
from_signals_shortonly(
2784
close=close, entries=entries, exits=exits,
2785
open=open, high=high, low=low,
2786
sl_stop=[[np.nan, 0.1, 0.15, 0.2, np.inf]]).order_records,
2787
np.array([
2788
(0, 0, 0, 20.0, 5.0, 0.0, 1),
2789
(1, 1, 0, 20.0, 5.0, 0.0, 1),
2790
(2, 2, 0, 20.0, 5.0, 0.0, 1),
2791
(3, 3, 0, 20.0, 5.0, 0.0, 1),
2792
(4, 4, 0, 20.0, 5.0, 0.0, 1)
2793
], dtype=order_dt)
2794
)
2795
2796
close = pd.Series([1., 2., 3., 4., 5.], index=price.index)
2797
open = close - 0.25
2798
high = close + 0.5
2799
low = close - 0.5
2800
record_arrays_close(
2801
from_signals_longonly(
2802
close=close, entries=entries, exits=exits,
2803
sl_stop=[[np.nan, 0.5, 3., np.inf]]).order_records,
2804
np.array([
2805
(0, 0, 0, 100.0, 1.0, 0.0, 0),
2806
(1, 1, 0, 100.0, 1.0, 0.0, 0),
2807
(2, 2, 0, 100.0, 1.0, 0.0, 0),
2808
(3, 3, 0, 100.0, 1.0, 0.0, 0)
2809
], dtype=order_dt)
2810
)
2811
record_arrays_close(
2812
from_signals_shortonly(
2813
close=close, entries=entries, exits=exits,
2814
sl_stop=[[np.nan, 0.5, 3., np.inf]]).order_records,
2815
np.array([
2816
(0, 0, 0, 100.0, 1.0, 0.0, 1),
2817
(1, 1, 0, 100.0, 1.0, 0.0, 1), (2, 1, 1, 100.0, 2.0, 0.0, 0),
2818
(3, 2, 0, 100.0, 1.0, 0.0, 1), (4, 2, 3, 50.0, 4.0, 0.0, 0),
2819
(5, 3, 0, 100.0, 1.0, 0.0, 1)
2820
], dtype=order_dt)
2821
)
2822
record_arrays_close(
2823
from_signals_both(
2824
close=close, entries=entries, exits=exits,
2825
sl_stop=[[np.nan, 0.5, 3., np.inf]]).order_records,
2826
from_signals_longonly(
2827
close=close, entries=entries, exits=exits,
2828
sl_stop=[[np.nan, 0.5, 3., np.inf]]).order_records
2829
)
2830
record_arrays_close(
2831
from_signals_both(
2832
close=close, entries=exits, exits=entries,
2833
sl_stop=[[np.nan, 0.5, 3., np.inf]]).order_records,
2834
from_signals_shortonly(
2835
close=close, entries=entries, exits=exits,
2836
sl_stop=[[np.nan, 0.5, 3., np.inf]]).order_records
2837
)
2838
record_arrays_close(
2839
from_signals_longonly(
2840
close=close, entries=entries, exits=exits,
2841
open=open, high=high, low=low,
2842
sl_stop=[[np.nan, 0.5, 0.75, 1., np.inf]]).order_records,
2843
np.array([
2844
(0, 0, 0, 100.0, 1.0, 0.0, 0),
2845
(1, 1, 0, 100.0, 1.0, 0.0, 0),
2846
(2, 2, 0, 100.0, 1.0, 0.0, 0),
2847
(3, 3, 0, 100.0, 1.0, 0.0, 0),
2848
(4, 4, 0, 100.0, 1.0, 0.0, 0)
2849
], dtype=order_dt)
2850
)
2851
record_arrays_close(
2852
from_signals_shortonly(
2853
close=close, entries=entries, exits=exits,
2854
open=open, high=high, low=low,
2855
sl_stop=[[np.nan, 0.5, 0.75, 1., np.inf]]).order_records,
2856
np.array([
2857
(0, 0, 0, 100.0, 1.0, 0.0, 1),
2858
(1, 1, 0, 100.0, 1.0, 0.0, 1), (2, 1, 1, 100.0, 1.75, 0.0, 0),
2859
(3, 2, 0, 100.0, 1.0, 0.0, 1), (4, 2, 1, 100.0, 1.75, 0.0, 0),
2860
(5, 3, 0, 100.0, 1.0, 0.0, 1), (6, 3, 1, 100.0, 2.0, 0.0, 0),
2861
(7, 4, 0, 100.0, 1.0, 0.0, 1)
2862
], dtype=order_dt)
2863
)
2864
2865
def test_ts_stop(self):
2866
entries = pd.Series([True, False, False, False, False], index=price.index)
2867
exits = pd.Series([False, False, False, False, False], index=price.index)
2868
2869
with pytest.raises(Exception):
2870
_ = from_signals_both(ts_stop=-0.1)
2871
2872
close = pd.Series([4., 5., 4., 3., 2.], index=price.index)
2873
open = close + 0.25
2874
high = close + 0.5
2875
low = close - 0.5
2876
record_arrays_close(
2877
from_signals_longonly(
2878
close=close, entries=entries, exits=exits,
2879
sl_stop=[[np.nan, 0.1, 0.5, np.inf]], sl_trail=True).order_records,
2880
np.array([
2881
(0, 0, 0, 25.0, 4.0, 0.0, 0),
2882
(1, 1, 0, 25.0, 4.0, 0.0, 0), (2, 1, 2, 25.0, 4.0, 0.0, 1),
2883
(3, 2, 0, 25.0, 4.0, 0.0, 0), (4, 2, 4, 25.0, 2.0, 0.0, 1),
2884
(5, 3, 0, 25.0, 4.0, 0.0, 0)
2885
], dtype=order_dt)
2886
)
2887
record_arrays_close(
2888
from_signals_shortonly(
2889
close=close, entries=entries, exits=exits,
2890
sl_stop=[[np.nan, 0.1, 0.5, np.inf]], sl_trail=True).order_records,
2891
np.array([
2892
(0, 0, 0, 25.0, 4.0, 0.0, 1),
2893
(1, 1, 0, 25.0, 4.0, 0.0, 1), (2, 1, 1, 25.0, 5.0, 0.0, 0),
2894
(3, 2, 0, 25.0, 4.0, 0.0, 1),
2895
(4, 3, 0, 25.0, 4.0, 0.0, 1)
2896
], dtype=order_dt)
2897
)
2898
record_arrays_close(
2899
from_signals_both(
2900
close=close, entries=entries, exits=exits,
2901
sl_stop=[[np.nan, 0.1, 0.5, np.inf]], sl_trail=True).order_records,
2902
from_signals_longonly(
2903
close=close, entries=entries, exits=exits,
2904
sl_stop=[[np.nan, 0.1, 0.5, np.inf]], sl_trail=True).order_records
2905
)
2906
print('here')
2907
record_arrays_close(
2908
from_signals_both(
2909
close=close, entries=exits, exits=entries,
2910
sl_stop=[[np.nan, 0.1, 0.5, np.inf]], sl_trail=True).order_records,
2911
from_signals_shortonly(
2912
close=close, entries=entries, exits=exits,
2913
sl_stop=[[np.nan, 0.1, 0.5, np.inf]], sl_trail=True).order_records
2914
)
2915
record_arrays_close(
2916
from_signals_longonly(
2917
close=close, entries=entries, exits=exits,
2918
open=open, high=high, low=low,
2919
sl_stop=[[np.nan, 0.15, 0.2, 0.25, np.inf]], sl_trail=True).order_records,
2920
np.array([
2921
(0, 0, 0, 25.0, 4.0, 0.0, 0),
2922
(1, 1, 0, 25.0, 4.0, 0.0, 0), (2, 1, 2, 25.0, 4.25, 0.0, 1),
2923
(3, 2, 0, 25.0, 4.0, 0.0, 0), (4, 2, 2, 25.0, 4.25, 0.0, 1),
2924
(5, 3, 0, 25.0, 4.0, 0.0, 0), (6, 3, 2, 25.0, 4.125, 0.0, 1),
2925
(7, 4, 0, 25.0, 4.0, 0.0, 0)
2926
], dtype=order_dt)
2927
)
2928
record_arrays_close(
2929
from_signals_shortonly(
2930
close=close, entries=entries, exits=exits,
2931
open=open, high=high, low=low,
2932
sl_stop=[[np.nan, 0.15, 0.2, 0.25, np.inf]], sl_trail=True).order_records,
2933
np.array([
2934
(0, 0, 0, 25.0, 4.0, 0.0, 1),
2935
(1, 1, 0, 25.0, 4.0, 0.0, 1), (2, 1, 1, 25.0, 5.25, 0.0, 0),
2936
(3, 2, 0, 25.0, 4.0, 0.0, 1), (4, 2, 1, 25.0, 5.25, 0.0, 0),
2937
(5, 3, 0, 25.0, 4.0, 0.0, 1), (6, 3, 1, 25.0, 5.25, 0.0, 0),
2938
(7, 4, 0, 25.0, 4.0, 0.0, 1)
2939
], dtype=order_dt)
2940
)
2941
2942
close = pd.Series([2., 1., 2., 3., 4.], index=price.index)
2943
open = close - 0.25
2944
high = close + 0.5
2945
low = close - 0.5
2946
record_arrays_close(
2947
from_signals_longonly(
2948
close=close, entries=entries, exits=exits,
2949
sl_stop=[[np.nan, 0.5, 3., np.inf]], sl_trail=True).order_records,
2950
np.array([
2951
(0, 0, 0, 50.0, 2.0, 0.0, 0),
2952
(1, 1, 0, 50.0, 2.0, 0.0, 0), (2, 1, 1, 50.0, 1.0, 0.0, 1),
2953
(3, 2, 0, 50.0, 2.0, 0.0, 0),
2954
(4, 3, 0, 50.0, 2.0, 0.0, 0)
2955
], dtype=order_dt)
2956
)
2957
record_arrays_close(
2958
from_signals_shortonly(
2959
close=close, entries=entries, exits=exits,
2960
sl_stop=[[np.nan, 0.5, 3., np.inf]], sl_trail=True).order_records,
2961
np.array([
2962
(0, 0, 0, 50.0, 2.0, 0.0, 1),
2963
(1, 1, 0, 50.0, 2.0, 0.0, 1), (2, 1, 2, 50.0, 2.0, 0.0, 0),
2964
(3, 2, 0, 50.0, 2.0, 0.0, 1), (4, 2, 4, 50.0, 4.0, 0.0, 0),
2965
(5, 3, 0, 50.0, 2.0, 0.0, 1)
2966
], dtype=order_dt)
2967
)
2968
record_arrays_close(
2969
from_signals_both(
2970
close=close, entries=entries, exits=exits,
2971
sl_stop=[[np.nan, 0.5, 3., np.inf]], sl_trail=True).order_records,
2972
from_signals_longonly(
2973
close=close, entries=entries, exits=exits,
2974
sl_stop=[[np.nan, 0.5, 3., np.inf]], sl_trail=True).order_records
2975
)
2976
record_arrays_close(
2977
from_signals_both(
2978
close=close, entries=exits, exits=entries,
2979
sl_stop=[[np.nan, 0.5, 3., np.inf]], sl_trail=True).order_records,
2980
from_signals_shortonly(
2981
close=close, entries=entries, exits=exits,
2982
sl_stop=[[np.nan, 0.5, 3., np.inf]], sl_trail=True).order_records
2983
)
2984
record_arrays_close(
2985
from_signals_longonly(
2986
close=close, entries=entries, exits=exits,
2987
open=open, high=high, low=low,
2988
sl_stop=[[np.nan, 0.5, 0.75, 1., np.inf]], sl_trail=True).order_records,
2989
np.array([
2990
(0, 0, 0, 50.0, 2.0, 0.0, 0),
2991
(1, 1, 0, 50.0, 2.0, 0.0, 0), (2, 1, 1, 50.0, 0.75, 0.0, 1),
2992
(3, 2, 0, 50.0, 2.0, 0.0, 0), (4, 2, 1, 50.0, 0.5, 0.0, 1),
2993
(5, 3, 0, 50.0, 2.0, 0.0, 0),
2994
(6, 4, 0, 50.0, 2.0, 0.0, 0)
2995
], dtype=order_dt)
2996
)
2997
record_arrays_close(
2998
from_signals_shortonly(
2999
close=close, entries=entries, exits=exits,
3000
open=open, high=high, low=low,
3001
sl_stop=[[np.nan, 0.5, 0.75, 1., np.inf]], sl_trail=True).order_records,
3002
np.array([
3003
(0, 0, 0, 50.0, 2.0, 0.0, 1),
3004
(1, 1, 0, 50.0, 2.0, 0.0, 1), (2, 1, 2, 50.0, 1.75, 0.0, 0),
3005
(3, 2, 0, 50.0, 2.0, 0.0, 1), (4, 2, 2, 50.0, 1.75, 0.0, 0),
3006
(5, 3, 0, 50.0, 2.0, 0.0, 1), (6, 3, 2, 50.0, 1.75, 0.0, 0),
3007
(7, 4, 0, 50.0, 2.0, 0.0, 1)
3008
], dtype=order_dt)
3009
)
3010
3011
def test_tp_stop(self):
3012
entries = pd.Series([True, False, False, False, False], index=price.index)
3013
exits = pd.Series([False, False, False, False, False], index=price.index)
3014
3015
with pytest.raises(Exception):
3016
_ = from_signals_both(sl_stop=-0.1)
3017
3018
close = pd.Series([5., 4., 3., 2., 1.], index=price.index)
3019
open = close + 0.25
3020
high = close + 0.5
3021
low = close - 0.5
3022
record_arrays_close(
3023
from_signals_longonly(
3024
close=close, entries=entries, exits=exits,
3025
tp_stop=[[np.nan, 0.1, 0.5, np.inf]]).order_records,
3026
np.array([
3027
(0, 0, 0, 20.0, 5.0, 0.0, 0),
3028
(1, 1, 0, 20.0, 5.0, 0.0, 0),
3029
(2, 2, 0, 20.0, 5.0, 0.0, 0),
3030
(3, 3, 0, 20.0, 5.0, 0.0, 0)
3031
], dtype=order_dt)
3032
)
3033
record_arrays_close(
3034
from_signals_shortonly(
3035
close=close, entries=entries, exits=exits,
3036
tp_stop=[[np.nan, 0.1, 0.5, np.inf]]).order_records,
3037
np.array([
3038
(0, 0, 0, 20.0, 5.0, 0.0, 1),
3039
(1, 1, 0, 20.0, 5.0, 0.0, 1), (2, 1, 1, 20.0, 4.0, 0.0, 0),
3040
(3, 2, 0, 20.0, 5.0, 0.0, 1), (4, 2, 3, 20.0, 2.0, 0.0, 0),
3041
(5, 3, 0, 20.0, 5.0, 0.0, 1)
3042
], dtype=order_dt)
3043
)
3044
record_arrays_close(
3045
from_signals_both(
3046
close=close, entries=entries, exits=exits,
3047
tp_stop=[[np.nan, 0.1, 0.5, np.inf]]).order_records,
3048
from_signals_longonly(
3049
close=close, entries=entries, exits=exits,
3050
tp_stop=[[np.nan, 0.1, 0.5, np.inf]]).order_records
3051
)
3052
record_arrays_close(
3053
from_signals_both(
3054
close=close, entries=exits, exits=entries,
3055
tp_stop=[[np.nan, 0.1, 0.5, np.inf]]).order_records,
3056
from_signals_shortonly(
3057
close=close, entries=entries, exits=exits,
3058
tp_stop=[[np.nan, 0.1, 0.5, np.inf]]).order_records
3059
)
3060
record_arrays_close(
3061
from_signals_longonly(
3062
close=close, entries=entries, exits=exits,
3063
open=open, high=high, low=low,
3064
tp_stop=[[np.nan, 0.1, 0.15, 0.2, np.inf]]).order_records,
3065
np.array([
3066
(0, 0, 0, 20.0, 5.0, 0.0, 0),
3067
(1, 1, 0, 20.0, 5.0, 0.0, 0),
3068
(2, 2, 0, 20.0, 5.0, 0.0, 0),
3069
(3, 3, 0, 20.0, 5.0, 0.0, 0),
3070
(4, 4, 0, 20.0, 5.0, 0.0, 0)
3071
], dtype=order_dt)
3072
)
3073
record_arrays_close(
3074
from_signals_shortonly(
3075
close=close, entries=entries, exits=exits,
3076
open=open, high=high, low=low,
3077
tp_stop=[[np.nan, 0.1, 0.15, 0.2, np.inf]]).order_records,
3078
np.array([
3079
(0, 0, 0, 20.0, 5.0, 0.0, 1),
3080
(1, 1, 0, 20.0, 5.0, 0.0, 1), (2, 1, 1, 20.0, 4.25, 0.0, 0),
3081
(3, 2, 0, 20.0, 5.0, 0.0, 1), (4, 2, 1, 20.0, 4.25, 0.0, 0),
3082
(5, 3, 0, 20.0, 5.0, 0.0, 1), (6, 3, 1, 20.0, 4.0, 0.0, 0),
3083
(7, 4, 0, 20.0, 5.0, 0.0, 1)
3084
], dtype=order_dt)
3085
)
3086
3087
close = pd.Series([1., 2., 3., 4., 5.], index=price.index)
3088
open = close - 0.25
3089
high = close + 0.5
3090
low = close - 0.5
3091
record_arrays_close(
3092
from_signals_longonly(
3093
close=close, entries=entries, exits=exits,
3094
tp_stop=[[np.nan, 0.5, 3., np.inf]]).order_records,
3095
np.array([
3096
(0, 0, 0, 100.0, 1.0, 0.0, 0),
3097
(1, 1, 0, 100.0, 1.0, 0.0, 0), (2, 1, 1, 100.0, 2.0, 0.0, 1),
3098
(3, 2, 0, 100.0, 1.0, 0.0, 0), (4, 2, 3, 100.0, 4.0, 0.0, 1),
3099
(5, 3, 0, 100.0, 1.0, 0.0, 0)
3100
], dtype=order_dt)
3101
)
3102
record_arrays_close(
3103
from_signals_shortonly(
3104
close=close, entries=entries, exits=exits,
3105
tp_stop=[[np.nan, 0.5, 3., np.inf]]).order_records,
3106
np.array([
3107
(0, 0, 0, 100.0, 1.0, 0.0, 1),
3108
(1, 1, 0, 100.0, 1.0, 0.0, 1),
3109
(2, 2, 0, 100.0, 1.0, 0.0, 1),
3110
(3, 3, 0, 100.0, 1.0, 0.0, 1)
3111
], dtype=order_dt)
3112
)
3113
record_arrays_close(
3114
from_signals_both(
3115
close=close, entries=entries, exits=exits,
3116
tp_stop=[[np.nan, 0.5, 3., np.inf]]).order_records,
3117
from_signals_longonly(
3118
close=close, entries=entries, exits=exits,
3119
tp_stop=[[np.nan, 0.5, 3., np.inf]]).order_records
3120
)
3121
record_arrays_close(
3122
from_signals_both(
3123
close=close, entries=exits, exits=entries,
3124
tp_stop=[[np.nan, 0.5, 3., np.inf]]).order_records,
3125
from_signals_shortonly(
3126
close=close, entries=entries, exits=exits,
3127
tp_stop=[[np.nan, 0.5, 3., np.inf]]).order_records
3128
)
3129
record_arrays_close(
3130
from_signals_longonly(
3131
close=close, entries=entries, exits=exits,
3132
open=open, high=high, low=low,
3133
tp_stop=[[np.nan, 0.5, 0.75, 1., np.inf]]).order_records,
3134
np.array([
3135
(0, 0, 0, 100.0, 1.0, 0.0, 0),
3136
(1, 1, 0, 100.0, 1.0, 0.0, 0), (2, 1, 1, 100.0, 1.75, 0.0, 1),
3137
(3, 2, 0, 100.0, 1.0, 0.0, 0), (4, 2, 1, 100.0, 1.75, 0.0, 1),
3138
(5, 3, 0, 100.0, 1.0, 0.0, 0), (6, 3, 1, 100.0, 2.0, 0.0, 1),
3139
(7, 4, 0, 100.0, 1.0, 0.0, 0)
3140
], dtype=order_dt)
3141
)
3142
record_arrays_close(
3143
from_signals_shortonly(
3144
close=close, entries=entries, exits=exits,
3145
open=open, high=high, low=low,
3146
tp_stop=[[np.nan, 0.5, 0.75, 1., np.inf]]).order_records,
3147
np.array([
3148
(0, 0, 0, 100.0, 1.0, 0.0, 1),
3149
(1, 1, 0, 100.0, 1.0, 0.0, 1),
3150
(2, 2, 0, 100.0, 1.0, 0.0, 1),
3151
(3, 3, 0, 100.0, 1.0, 0.0, 1),
3152
(4, 4, 0, 100.0, 1.0, 0.0, 1)
3153
], dtype=order_dt)
3154
)
3155
3156
def test_stop_entry_price(self):
3157
entries = pd.Series([True, False, False, False, False], index=price.index)
3158
exits = pd.Series([False, False, False, False, False], index=price.index)
3159
close = pd.Series([5., 4., 3., 2., 1.], index=price.index)
3160
open = close + 0.25
3161
high = close + 0.5
3162
low = close - 0.5
3163
3164
record_arrays_close(
3165
from_signals_longonly(
3166
close=close, entries=entries, exits=exits,
3167
open=open, high=high, low=low,
3168
sl_stop=[[0.05, 0.5, 0.75]], price=1.1 * close, val_price=1.05 * close,
3169
stop_entry_price='val_price',
3170
stop_exit_price='stoplimit', slippage=0.1).order_records,
3171
np.array([
3172
(0, 0, 0, 16.52892561983471, 6.050000000000001, 0.0, 0),
3173
(1, 0, 1, 16.52892561983471, 4.25, 0.0, 1),
3174
(2, 1, 0, 16.52892561983471, 6.050000000000001, 0.0, 0),
3175
(3, 1, 2, 16.52892561983471, 2.625, 0.0, 1),
3176
(4, 2, 0, 16.52892561983471, 6.050000000000001, 0.0, 0),
3177
(5, 2, 4, 16.52892561983471, 1.25, 0.0, 1)
3178
], dtype=order_dt)
3179
)
3180
record_arrays_close(
3181
from_signals_longonly(
3182
close=close, entries=entries, exits=exits,
3183
open=open, high=high, low=low,
3184
sl_stop=[[0.05, 0.5, 0.75]], price=1.1 * close, val_price=1.05 * close,
3185
stop_entry_price='price',
3186
stop_exit_price='stoplimit', slippage=0.1).order_records,
3187
np.array([
3188
(0, 0, 0, 16.52892561983471, 6.050000000000001, 0.0, 0),
3189
(1, 0, 1, 16.52892561983471, 4.25, 0.0, 1),
3190
(2, 1, 0, 16.52892561983471, 6.050000000000001, 0.0, 0),
3191
(3, 1, 2, 16.52892561983471, 2.75, 0.0, 1),
3192
(4, 2, 0, 16.52892561983471, 6.050000000000001, 0.0, 0),
3193
(5, 2, 4, 16.52892561983471, 1.25, 0.0, 1)
3194
], dtype=order_dt)
3195
)
3196
record_arrays_close(
3197
from_signals_longonly(
3198
close=close, entries=entries, exits=exits,
3199
open=open, high=high, low=low,
3200
sl_stop=[[0.05, 0.5, 0.75]], price=1.1 * close, val_price=1.05 * close,
3201
stop_entry_price='fillprice',
3202
stop_exit_price='stoplimit', slippage=0.1).order_records,
3203
np.array([
3204
(0, 0, 0, 16.52892561983471, 6.050000000000001, 0.0, 0),
3205
(1, 0, 1, 16.52892561983471, 4.25, 0.0, 1),
3206
(2, 1, 0, 16.52892561983471, 6.050000000000001, 0.0, 0),
3207
(3, 1, 2, 16.52892561983471, 3.0250000000000004, 0.0, 1),
3208
(4, 2, 0, 16.52892561983471, 6.050000000000001, 0.0, 0),
3209
(5, 2, 3, 16.52892561983471, 1.5125000000000002, 0.0, 1)
3210
], dtype=order_dt)
3211
)
3212
record_arrays_close(
3213
from_signals_longonly(
3214
close=close, entries=entries, exits=exits,
3215
open=open, high=high, low=low,
3216
sl_stop=[[0.05, 0.5, 0.75]], price=1.1 * close, val_price=1.05 * close,
3217
stop_entry_price='close',
3218
stop_exit_price='stoplimit', slippage=0.1).order_records,
3219
np.array([
3220
(0, 0, 0, 16.52892561983471, 6.050000000000001, 0.0, 0),
3221
(1, 0, 1, 16.52892561983471, 4.25, 0.0, 1),
3222
(2, 1, 0, 16.52892561983471, 6.050000000000001, 0.0, 0),
3223
(3, 1, 2, 16.52892561983471, 2.5, 0.0, 1),
3224
(4, 2, 0, 16.52892561983471, 6.050000000000001, 0.0, 0),
3225
(5, 2, 4, 16.52892561983471, 1.25, 0.0, 1)
3226
], dtype=order_dt)
3227
)
3228
3229
def test_stop_exit_price(self):
3230
entries = pd.Series([True, False, False, False, False], index=price.index)
3231
exits = pd.Series([False, False, False, False, False], index=price.index)
3232
close = pd.Series([5., 4., 3., 2., 1.], index=price.index)
3233
open = close + 0.25
3234
high = close + 0.5
3235
low = close - 0.5
3236
3237
record_arrays_close(
3238
from_signals_longonly(
3239
close=close, entries=entries, exits=exits,
3240
open=open, high=high, low=low,
3241
sl_stop=[[0.05, 0.5, 0.75]], price=1.1 * close,
3242
stop_exit_price='stoplimit', slippage=0.1).order_records,
3243
np.array([
3244
(0, 0, 0, 16.528926, 6.05, 0.0, 0), (1, 0, 1, 16.528926, 4.25, 0.0, 1),
3245
(2, 1, 0, 16.528926, 6.05, 0.0, 0), (3, 1, 2, 16.528926, 2.5, 0.0, 1),
3246
(4, 2, 0, 16.528926, 6.05, 0.0, 0), (5, 2, 4, 16.528926, 1.25, 0.0, 1)
3247
], dtype=order_dt)
3248
)
3249
record_arrays_close(
3250
from_signals_longonly(
3251
close=close, entries=entries, exits=exits,
3252
open=open, high=high, low=low,
3253
sl_stop=[[0.05, 0.5, 0.75]], price=1.1 * close,
3254
stop_exit_price='stopmarket', slippage=0.1).order_records,
3255
np.array([
3256
(0, 0, 0, 16.528926, 6.05, 0.0, 0), (1, 0, 1, 16.528926, 3.825, 0.0, 1),
3257
(2, 1, 0, 16.528926, 6.05, 0.0, 0), (3, 1, 2, 16.528926, 2.25, 0.0, 1),
3258
(4, 2, 0, 16.528926, 6.05, 0.0, 0), (5, 2, 4, 16.528926, 1.125, 0.0, 1)
3259
], dtype=order_dt)
3260
)
3261
record_arrays_close(
3262
from_signals_longonly(
3263
close=close, entries=entries, exits=exits,
3264
open=open, high=high, low=low,
3265
sl_stop=[[0.05, 0.5, 0.75]], price=1.1 * close,
3266
stop_exit_price='close', slippage=0.1).order_records,
3267
np.array([
3268
(0, 0, 0, 16.528926, 6.05, 0.0, 0), (1, 0, 1, 16.528926, 3.6, 0.0, 1),
3269
(2, 1, 0, 16.528926, 6.05, 0.0, 0), (3, 1, 2, 16.528926, 2.7, 0.0, 1),
3270
(4, 2, 0, 16.528926, 6.05, 0.0, 0), (5, 2, 4, 16.528926, 0.9, 0.0, 1)
3271
], dtype=order_dt)
3272
)
3273
record_arrays_close(
3274
from_signals_longonly(
3275
close=close, entries=entries, exits=exits,
3276
open=open, high=high, low=low,
3277
sl_stop=[[0.05, 0.5, 0.75]], price=1.1 * close,
3278
stop_exit_price='price', slippage=0.1).order_records,
3279
np.array([
3280
(0, 0, 0, 16.528926, 6.05, 0.0, 0), (1, 0, 1, 16.528926, 3.9600000000000004, 0.0, 1),
3281
(2, 1, 0, 16.528926, 6.05, 0.0, 0), (3, 1, 2, 16.528926, 2.97, 0.0, 1),
3282
(4, 2, 0, 16.528926, 6.05, 0.0, 0), (5, 2, 4, 16.528926, 0.9900000000000001, 0.0, 1)
3283
], dtype=order_dt)
3284
)
3285
3286
def test_upon_stop_exit(self):
3287
entries = pd.Series([True, False, False, False, False], index=price.index)
3288
exits = pd.Series([False, False, False, False, False], index=price.index)
3289
close = pd.Series([5., 4., 3., 2., 1.], index=price.index)
3290
record_arrays_close(
3291
from_signals_both(
3292
close=close, entries=entries, exits=exits, size=1,
3293
sl_stop=0.1, upon_stop_exit=[['close', 'closereduce', 'reverse', 'reversereduce']],
3294
accumulate=True).order_records,
3295
np.array([
3296
(0, 0, 0, 1.0, 5.0, 0.0, 0), (1, 0, 1, 1.0, 4.0, 0.0, 1),
3297
(2, 1, 0, 1.0, 5.0, 0.0, 0), (3, 1, 1, 1.0, 4.0, 0.0, 1),
3298
(4, 2, 0, 1.0, 5.0, 0.0, 0), (5, 2, 1, 2.0, 4.0, 0.0, 1),
3299
(6, 3, 0, 1.0, 5.0, 0.0, 0), (7, 3, 1, 1.0, 4.0, 0.0, 1)
3300
], dtype=order_dt)
3301
)
3302
record_arrays_close(
3303
from_signals_both(
3304
close=close, entries=entries, exits=exits, size=1,
3305
sl_stop=0.1, upon_stop_exit=[['close', 'closereduce', 'reverse', 'reversereduce']]).order_records,
3306
np.array([
3307
(0, 0, 0, 1.0, 5.0, 0.0, 0), (1, 0, 1, 1.0, 4.0, 0.0, 1),
3308
(2, 1, 0, 1.0, 5.0, 0.0, 0), (3, 1, 1, 1.0, 4.0, 0.0, 1),
3309
(4, 2, 0, 1.0, 5.0, 0.0, 0), (5, 2, 1, 2.0, 4.0, 0.0, 1),
3310
(6, 3, 0, 1.0, 5.0, 0.0, 0), (7, 3, 1, 2.0, 4.0, 0.0, 1)
3311
], dtype=order_dt)
3312
)
3313
3314
def test_upon_stop_update(self):
3315
entries = pd.Series([True, True, False, False, False], index=price.index)
3316
exits = pd.Series([False, False, False, False, False], index=price.index)
3317
close = pd.Series([5., 4., 3., 2., 1.], index=price.index)
3318
sl_stop = pd.Series([0.4, np.nan, np.nan, np.nan, np.nan])
3319
record_arrays_close(
3320
from_signals_longonly(
3321
close=close, entries=entries, exits=exits, accumulate=True, size=1.,
3322
sl_stop=sl_stop, upon_stop_update=[['keep', 'override', 'overridenan']]).order_records,
3323
np.array([
3324
(0, 0, 0, 1.0, 5.0, 0.0, 0), (1, 0, 1, 1.0, 4.0, 0.0, 0), (2, 0, 2, 2.0, 3.0, 0.0, 1),
3325
(3, 1, 0, 1.0, 5.0, 0.0, 0), (4, 1, 1, 1.0, 4.0, 0.0, 0), (5, 1, 2, 2.0, 3.0, 0.0, 1),
3326
(6, 2, 0, 1.0, 5.0, 0.0, 0), (7, 2, 1, 1.0, 4.0, 0.0, 0)
3327
], dtype=order_dt)
3328
)
3329
sl_stop = pd.Series([0.4, 0.4, np.nan, np.nan, np.nan])
3330
record_arrays_close(
3331
from_signals_longonly(
3332
close=close, entries=entries, exits=exits, accumulate=True, size=1.,
3333
sl_stop=sl_stop, upon_stop_update=[['keep', 'override']]).order_records,
3334
np.array([
3335
(0, 0, 0, 1.0, 5.0, 0.0, 0), (1, 0, 1, 1.0, 4.0, 0.0, 0), (2, 0, 2, 2.0, 3.0, 0.0, 1),
3336
(3, 1, 0, 1.0, 5.0, 0.0, 0), (4, 1, 1, 1.0, 4.0, 0.0, 0), (5, 1, 3, 2.0, 2.0, 0.0, 1)
3337
], dtype=order_dt)
3338
)
3339
3340
def test_adjust_sl_func(self):
3341
entries = pd.Series([True, False, False, False, False], index=price.index)
3342
exits = pd.Series([False, False, False, False, False], index=price.index)
3343
close = pd.Series([5., 4., 3., 2., 1.], index=price.index)
3344
3345
@njit
3346
def adjust_sl_func_nb(c, dur):
3347
return 0. if c.i - c.init_i >= dur else c.curr_stop, c.curr_trail
3348
3349
record_arrays_close(
3350
from_signals_longonly(
3351
close=close, entries=entries, exits=exits,
3352
sl_stop=np.inf, adjust_sl_func_nb=adjust_sl_func_nb, adjust_sl_args=(2,)).order_records,
3353
np.array([
3354
(0, 0, 0, 20.0, 5.0, 0.0, 0), (1, 0, 2, 20.0, 3.0, 0.0, 1)
3355
], dtype=order_dt)
3356
)
3357
3358
def test_adjust_ts_func(self):
3359
entries = pd.Series([True, False, False, False, False], index=price.index)
3360
exits = pd.Series([False, False, False, False, False], index=price.index)
3361
close = pd.Series([10., 11., 12., 11., 10.], index=price.index)
3362
3363
@njit
3364
def adjust_sl_func_nb(c, dur):
3365
return 0. if c.i - c.curr_i >= dur else c.curr_stop, c.curr_trail
3366
3367
record_arrays_close(
3368
from_signals_longonly(
3369
close=close, entries=entries, exits=exits,
3370
sl_stop=np.inf, adjust_sl_func_nb=adjust_sl_func_nb, adjust_sl_args=(2,)).order_records,
3371
np.array([
3372
(0, 0, 0, 10.0, 10.0, 0.0, 0), (1, 0, 4, 10.0, 10.0, 0.0, 1)
3373
], dtype=order_dt)
3374
)
3375
3376
def test_adjust_tp_func(self):
3377
entries = pd.Series([True, False, False, False, False], index=price.index)
3378
exits = pd.Series([False, False, False, False, False], index=price.index)
3379
close = pd.Series([1., 2., 3., 4., 5.], index=price.index)
3380
3381
@njit
3382
def adjust_tp_func_nb(c, dur):
3383
return 0. if c.i - c.init_i >= dur else c.curr_stop
3384
3385
record_arrays_close(
3386
from_signals_longonly(
3387
close=close, entries=entries, exits=exits,
3388
tp_stop=np.inf, adjust_tp_func_nb=adjust_tp_func_nb, adjust_tp_args=(2,)).order_records,
3389
np.array([
3390
(0, 0, 0, 100.0, 1.0, 0.0, 0), (1, 0, 2, 100.0, 3.0, 0.0, 1)
3391
], dtype=order_dt)
3392
)
3393
3394
def test_max_orders(self):
3395
_ = from_signals_both(close=price_wide)
3396
_ = from_signals_both(close=price_wide, max_orders=6)
3397
with pytest.raises(Exception):
3398
_ = from_signals_both(close=price_wide, max_orders=5)
3399
3400
def test_max_logs(self):
3401
_ = from_signals_both(close=price_wide, log=True)
3402
_ = from_signals_both(close=price_wide, log=True, max_logs=6)
3403
with pytest.raises(Exception):
3404
_ = from_signals_both(close=price_wide, log=True, max_logs=5)
3405
3406
3407
# ############# from_holding ############# #
3408
3409
class TestFromHolding:
3410
def test_from_holding(self):
3411
record_arrays_close(
3412
vbt.Portfolio.from_holding(price).order_records,
3413
vbt.Portfolio.from_signals(price, True, False, accumulate=False).order_records
3414
)
3415
3416
3417
# ############# from_random_signals ############# #
3418
3419
class TestFromRandomSignals:
3420
def test_from_random_n(self):
3421
result = vbt.Portfolio.from_random_signals(price, n=2, seed=seed)
3422
record_arrays_close(
3423
result.order_records,
3424
vbt.Portfolio.from_signals(
3425
price,
3426
[True, False, True, False, False],
3427
[False, True, False, False, True]
3428
).order_records
3429
)
3430
pd.testing.assert_index_equal(
3431
result.wrapper.index,
3432
price.vbt.wrapper.index
3433
)
3434
pd.testing.assert_index_equal(
3435
result.wrapper.columns,
3436
price.vbt.wrapper.columns
3437
)
3438
result = vbt.Portfolio.from_random_signals(price, n=[1, 2], seed=seed)
3439
record_arrays_close(
3440
result.order_records,
3441
vbt.Portfolio.from_signals(
3442
price,
3443
[[False, True], [True, False], [False, True], [False, False], [False, False]],
3444
[[False, False], [False, True], [False, False], [False, True], [True, False]]
3445
).order_records
3446
)
3447
pd.testing.assert_index_equal(
3448
result.wrapper.index,
3449
pd.DatetimeIndex([
3450
'2020-01-01', '2020-01-02', '2020-01-03', '2020-01-04', '2020-01-05'
3451
], dtype='datetime64[ns]', freq=None)
3452
)
3453
pd.testing.assert_index_equal(
3454
result.wrapper.columns,
3455
pd.Index([1, 2], dtype='int64', name='randnx_n')
3456
)
3457
3458
def test_from_random_prob(self):
3459
result = vbt.Portfolio.from_random_signals(price, prob=0.5, seed=seed)
3460
record_arrays_close(
3461
result.order_records,
3462
vbt.Portfolio.from_signals(
3463
price,
3464
[True, False, False, False, False],
3465
[False, False, False, False, True]
3466
).order_records
3467
)
3468
pd.testing.assert_index_equal(
3469
result.wrapper.index,
3470
price.vbt.wrapper.index
3471
)
3472
pd.testing.assert_index_equal(
3473
result.wrapper.columns,
3474
price.vbt.wrapper.columns
3475
)
3476
result = vbt.Portfolio.from_random_signals(price, prob=[0.25, 0.5], seed=seed)
3477
record_arrays_close(
3478
result.order_records,
3479
vbt.Portfolio.from_signals(
3480
price,
3481
[[False, True], [False, False], [False, False], [False, False], [True, False]],
3482
[[False, False], [False, True], [False, False], [False, False], [False, False]]
3483
).order_records
3484
)
3485
pd.testing.assert_index_equal(
3486
result.wrapper.index,
3487
pd.DatetimeIndex([
3488
'2020-01-01', '2020-01-02', '2020-01-03', '2020-01-04', '2020-01-05'
3489
], dtype='datetime64[ns]', freq=None)
3490
)
3491
pd.testing.assert_index_equal(
3492
result.wrapper.columns,
3493
pd.MultiIndex.from_tuples(
3494
[(0.25, 0.25), (0.5, 0.5)],
3495
names=['rprobnx_entry_prob', 'rprobnx_exit_prob'])
3496
)
3497
3498
3499
# ############# from_order_func ############# #
3500
3501
@njit
3502
def order_func_nb(c, size):
3503
_size = nb.get_elem_nb(c, size)
3504
return nb.order_nb(_size if c.i % 2 == 0 else -_size)
3505
3506
3507
@njit
3508
def log_order_func_nb(c, size):
3509
_size = nb.get_elem_nb(c, size)
3510
return nb.order_nb(_size if c.i % 2 == 0 else -_size, log=True)
3511
3512
3513
@njit
3514
def flex_order_func_nb(c, size):
3515
if c.call_idx < c.group_len:
3516
_size = nb.get_col_elem_nb(c, c.from_col + c.call_idx, size)
3517
return c.from_col + c.call_idx, nb.order_nb(_size if c.i % 2 == 0 else -_size)
3518
return -1, nb.order_nothing_nb()
3519
3520
3521
@njit
3522
def log_flex_order_func_nb(c, size):
3523
if c.call_idx < c.group_len:
3524
_size = nb.get_col_elem_nb(c, c.from_col + c.call_idx, size)
3525
return c.from_col + c.call_idx, nb.order_nb(_size if c.i % 2 == 0 else -_size, log=True)
3526
return -1, nb.order_nothing_nb()
3527
3528
3529
class TestFromOrderFunc:
3530
@pytest.mark.parametrize("test_row_wise", [False, True])
3531
@pytest.mark.parametrize("test_flexible", [False, True])
3532
def test_one_column(self, test_row_wise, test_flexible):
3533
order_func = flex_order_func_nb if test_flexible else order_func_nb
3534
pf = vbt.Portfolio.from_order_func(
3535
price.tolist(), order_func, np.asarray(np.inf), row_wise=test_row_wise, flexible=test_flexible)
3536
record_arrays_close(
3537
pf.order_records,
3538
np.array([
3539
(0, 0, 0, 100.0, 1.0, 0.0, 0), (1, 0, 1, 200.0, 2.0, 0.0, 1),
3540
(2, 0, 2, 133.33333333333334, 3.0, 0.0, 0), (3, 0, 3, 66.66666666666669, 4.0, 0.0, 1),
3541
(4, 0, 4, 53.33333333333335, 5.0, 0.0, 0)
3542
], dtype=order_dt)
3543
)
3544
pf = vbt.Portfolio.from_order_func(
3545
price, order_func, np.asarray(np.inf), row_wise=test_row_wise, flexible=test_flexible)
3546
record_arrays_close(
3547
pf.order_records,
3548
np.array([
3549
(0, 0, 0, 100.0, 1.0, 0.0, 0), (1, 0, 1, 200.0, 2.0, 0.0, 1),
3550
(2, 0, 2, 133.33333333333334, 3.0, 0.0, 0), (3, 0, 3, 66.66666666666669, 4.0, 0.0, 1),
3551
(4, 0, 4, 53.33333333333335, 5.0, 0.0, 0)
3552
], dtype=order_dt)
3553
)
3554
pd.testing.assert_index_equal(
3555
pf.wrapper.index,
3556
pd.DatetimeIndex(['2020-01-01', '2020-01-02', '2020-01-03', '2020-01-04', '2020-01-05'])
3557
)
3558
pd.testing.assert_index_equal(
3559
pf.wrapper.columns,
3560
pd.Index([0], dtype='int64')
3561
)
3562
assert pf.wrapper.ndim == 1
3563
assert pf.wrapper.freq == day_dt
3564
assert pf.wrapper.grouper.group_by is None
3565
3566
@pytest.mark.parametrize("test_row_wise", [False, True])
3567
@pytest.mark.parametrize("test_flexible", [False, True])
3568
@pytest.mark.parametrize("test_use_numba", [False, True])
3569
def test_multiple_columns(self, test_row_wise, test_flexible, test_use_numba):
3570
order_func = flex_order_func_nb if test_flexible else order_func_nb
3571
pf = vbt.Portfolio.from_order_func(
3572
price_wide, order_func, vbt.Rep('size'), broadcast_named_args=dict(size=[0, 1, np.inf]),
3573
row_wise=test_row_wise, flexible=test_flexible, use_numba=test_use_numba)
3574
if test_row_wise:
3575
record_arrays_close(
3576
pf.order_records,
3577
np.array([
3578
(0, 1, 0, 1.0, 1.0, 0.0, 0), (1, 2, 0, 100.0, 1.0, 0.0, 0),
3579
(2, 1, 1, 1.0, 2.0, 0.0, 1), (3, 2, 1, 200.0, 2.0, 0.0, 1),
3580
(4, 1, 2, 1.0, 3.0, 0.0, 0), (5, 2, 2, 133.33333333333334, 3.0, 0.0, 0),
3581
(6, 1, 3, 1.0, 4.0, 0.0, 1), (7, 2, 3, 66.66666666666669, 4.0, 0.0, 1),
3582
(8, 1, 4, 1.0, 5.0, 0.0, 0), (9, 2, 4, 53.33333333333335, 5.0, 0.0, 0)
3583
], dtype=order_dt)
3584
)
3585
else:
3586
record_arrays_close(
3587
pf.order_records,
3588
np.array([
3589
(0, 1, 0, 1.0, 1.0, 0.0, 0), (1, 1, 1, 1.0, 2.0, 0.0, 1),
3590
(2, 1, 2, 1.0, 3.0, 0.0, 0), (3, 1, 3, 1.0, 4.0, 0.0, 1),
3591
(4, 1, 4, 1.0, 5.0, 0.0, 0), (5, 2, 0, 100.0, 1.0, 0.0, 0),
3592
(6, 2, 1, 200.0, 2.0, 0.0, 1), (7, 2, 2, 133.33333333333334, 3.0, 0.0, 0),
3593
(8, 2, 3, 66.66666666666669, 4.0, 0.0, 1), (9, 2, 4, 53.33333333333335, 5.0, 0.0, 0)
3594
], dtype=order_dt)
3595
)
3596
pd.testing.assert_index_equal(
3597
pf.wrapper.index,
3598
pd.DatetimeIndex(['2020-01-01', '2020-01-02', '2020-01-03', '2020-01-04', '2020-01-05'])
3599
)
3600
pd.testing.assert_index_equal(
3601
pf.wrapper.columns,
3602
pd.Index(['a', 'b', 'c'], dtype='object')
3603
)
3604
assert pf.wrapper.ndim == 2
3605
assert pf.wrapper.freq == day_dt
3606
assert pf.wrapper.grouper.group_by is None
3607
3608
@pytest.mark.parametrize("test_row_wise", [False, True])
3609
@pytest.mark.parametrize("test_flexible", [False, True])
3610
def test_group_by(self, test_row_wise, test_flexible):
3611
order_func = flex_order_func_nb if test_flexible else order_func_nb
3612
pf = vbt.Portfolio.from_order_func(
3613
price_wide, order_func, np.asarray(np.inf),
3614
group_by=np.array([0, 0, 1]), row_wise=test_row_wise, flexible=test_flexible)
3615
if test_row_wise:
3616
record_arrays_close(
3617
pf.order_records,
3618
np.array([
3619
(0, 0, 0, 100.0, 1.0, 0.0, 0), (1, 1, 0, 100.0, 1.0, 0.0, 0),
3620
(2, 2, 0, 100.0, 1.0, 0.0, 0), (3, 0, 1, 200.0, 2.0, 0.0, 1),
3621
(4, 1, 1, 200.0, 2.0, 0.0, 1), (5, 2, 1, 200.0, 2.0, 0.0, 1),
3622
(6, 0, 2, 133.33333333333334, 3.0, 0.0, 0), (7, 1, 2, 133.33333333333334, 3.0, 0.0, 0),
3623
(8, 2, 2, 133.33333333333334, 3.0, 0.0, 0), (9, 0, 3, 66.66666666666669, 4.0, 0.0, 1),
3624
(10, 1, 3, 66.66666666666669, 4.0, 0.0, 1), (11, 2, 3, 66.66666666666669, 4.0, 0.0, 1),
3625
(12, 0, 4, 53.33333333333335, 5.0, 0.0, 0), (13, 1, 4, 53.33333333333335, 5.0, 0.0, 0),
3626
(14, 2, 4, 53.33333333333335, 5.0, 0.0, 0)
3627
], dtype=order_dt)
3628
)
3629
else:
3630
record_arrays_close(
3631
pf.order_records,
3632
np.array([
3633
(0, 0, 0, 100.0, 1.0, 0.0, 0), (1, 1, 0, 100.0, 1.0, 0.0, 0),
3634
(2, 0, 1, 200.0, 2.0, 0.0, 1), (3, 1, 1, 200.0, 2.0, 0.0, 1),
3635
(4, 0, 2, 133.33333333333334, 3.0, 0.0, 0), (5, 1, 2, 133.33333333333334, 3.0, 0.0, 0),
3636
(6, 0, 3, 66.66666666666669, 4.0, 0.0, 1), (7, 1, 3, 66.66666666666669, 4.0, 0.0, 1),
3637
(8, 0, 4, 53.33333333333335, 5.0, 0.0, 0), (9, 1, 4, 53.33333333333335, 5.0, 0.0, 0),
3638
(10, 2, 0, 100.0, 1.0, 0.0, 0), (11, 2, 1, 200.0, 2.0, 0.0, 1),
3639
(12, 2, 2, 133.33333333333334, 3.0, 0.0, 0), (13, 2, 3, 66.66666666666669, 4.0, 0.0, 1),
3640
(14, 2, 4, 53.33333333333335, 5.0, 0.0, 0)
3641
], dtype=order_dt)
3642
)
3643
pd.testing.assert_index_equal(
3644
pf.wrapper.grouper.group_by,
3645
pd.Index([0, 0, 1], dtype='int64')
3646
)
3647
pd.testing.assert_series_equal(
3648
pf.init_cash,
3649
pd.Series([200., 100.], index=pd.Index([0, 1], dtype='int64')).rename('init_cash')
3650
)
3651
assert not pf.cash_sharing
3652
3653
@pytest.mark.parametrize("test_row_wise", [False, True])
3654
@pytest.mark.parametrize("test_flexible", [False, True])
3655
def test_cash_sharing(self, test_row_wise, test_flexible):
3656
order_func = flex_order_func_nb if test_flexible else order_func_nb
3657
pf = vbt.Portfolio.from_order_func(
3658
price_wide, order_func, np.asarray(np.inf),
3659
group_by=np.array([0, 0, 1]), cash_sharing=True, row_wise=test_row_wise, flexible=test_flexible)
3660
if test_row_wise:
3661
record_arrays_close(
3662
pf.order_records,
3663
np.array([
3664
(0, 0, 0, 100., 1., 0., 0), (1, 2, 0, 100., 1., 0., 0),
3665
(2, 0, 1, 200., 2., 0., 1), (3, 2, 1, 200., 2., 0., 1),
3666
(4, 0, 2, 133.33333333, 3., 0., 0), (5, 2, 2, 133.33333333, 3., 0., 0),
3667
(6, 0, 3, 66.66666667, 4., 0., 1), (7, 2, 3, 66.66666667, 4., 0., 1),
3668
(8, 0, 4, 53.33333333, 5., 0., 0), (9, 2, 4, 53.33333333, 5., 0., 0)
3669
], dtype=order_dt)
3670
)
3671
else:
3672
record_arrays_close(
3673
pf.order_records,
3674
np.array([
3675
(0, 0, 0, 100., 1., 0., 0), (1, 0, 1, 200., 2., 0., 1),
3676
(2, 0, 2, 133.33333333, 3., 0., 0), (3, 0, 3, 66.66666667, 4., 0., 1),
3677
(4, 0, 4, 53.33333333, 5., 0., 0), (5, 2, 0, 100., 1., 0., 0),
3678
(6, 2, 1, 200., 2., 0., 1), (7, 2, 2, 133.33333333, 3., 0., 0),
3679
(8, 2, 3, 66.66666667, 4., 0., 1), (9, 2, 4, 53.33333333, 5., 0., 0)
3680
], dtype=order_dt)
3681
)
3682
pd.testing.assert_index_equal(
3683
pf.wrapper.grouper.group_by,
3684
pd.Index([0, 0, 1], dtype='int64')
3685
)
3686
pd.testing.assert_series_equal(
3687
pf.init_cash,
3688
pd.Series([100., 100.], index=pd.Index([0, 1], dtype='int64')).rename('init_cash')
3689
)
3690
assert pf.cash_sharing
3691
3692
@pytest.mark.parametrize(
3693
"test_row_wise",
3694
[False, True],
3695
)
3696
def test_call_seq(self, test_row_wise):
3697
pf = vbt.Portfolio.from_order_func(
3698
price_wide, order_func_nb, np.asarray(np.inf), group_by=np.array([0, 0, 1]),
3699
cash_sharing=True, row_wise=test_row_wise)
3700
if test_row_wise:
3701
record_arrays_close(
3702
pf.order_records,
3703
np.array([
3704
(0, 0, 0, 100., 1., 0., 0), (1, 2, 0, 100., 1., 0., 0),
3705
(2, 0, 1, 200., 2., 0., 1), (3, 2, 1, 200., 2., 0., 1),
3706
(4, 0, 2, 133.33333333, 3., 0., 0), (5, 2, 2, 133.33333333, 3., 0., 0),
3707
(6, 0, 3, 66.66666667, 4., 0., 1), (7, 2, 3, 66.66666667, 4., 0., 1),
3708
(8, 0, 4, 53.33333333, 5., 0., 0), (9, 2, 4, 53.33333333, 5., 0., 0)
3709
], dtype=order_dt)
3710
)
3711
else:
3712
record_arrays_close(
3713
pf.order_records,
3714
np.array([
3715
(0, 0, 0, 100., 1., 0., 0), (1, 0, 1, 200., 2., 0., 1),
3716
(2, 0, 2, 133.33333333, 3., 0., 0), (3, 0, 3, 66.66666667, 4., 0., 1),
3717
(4, 0, 4, 53.33333333, 5., 0., 0), (5, 2, 0, 100., 1., 0., 0),
3718
(6, 2, 1, 200., 2., 0., 1), (7, 2, 2, 133.33333333, 3., 0., 0),
3719
(8, 2, 3, 66.66666667, 4., 0., 1), (9, 2, 4, 53.33333333, 5., 0., 0)
3720
], dtype=order_dt)
3721
)
3722
np.testing.assert_array_equal(
3723
pf.call_seq.values,
3724
np.array([
3725
[0, 1, 0],
3726
[0, 1, 0],
3727
[0, 1, 0],
3728
[0, 1, 0],
3729
[0, 1, 0]
3730
])
3731
)
3732
pf = vbt.Portfolio.from_order_func(
3733
price_wide, order_func_nb, np.asarray(np.inf), group_by=np.array([0, 0, 1]),
3734
cash_sharing=True, call_seq='reversed', row_wise=test_row_wise)
3735
if test_row_wise:
3736
record_arrays_close(
3737
pf.order_records,
3738
np.array([
3739
(0, 1, 0, 100., 1., 0., 0), (1, 2, 0, 100., 1., 0., 0),
3740
(2, 1, 1, 200., 2., 0., 1), (3, 2, 1, 200., 2., 0., 1),
3741
(4, 1, 2, 133.33333333, 3., 0., 0), (5, 2, 2, 133.33333333, 3., 0., 0),
3742
(6, 1, 3, 66.66666667, 4., 0., 1), (7, 2, 3, 66.66666667, 4., 0., 1),
3743
(8, 1, 4, 53.33333333, 5., 0., 0), (9, 2, 4, 53.33333333, 5., 0., 0)
3744
], dtype=order_dt)
3745
)
3746
else:
3747
record_arrays_close(
3748
pf.order_records,
3749
np.array([
3750
(0, 1, 0, 100., 1., 0., 0), (1, 1, 1, 200., 2., 0., 1),
3751
(2, 1, 2, 133.33333333, 3., 0., 0), (3, 1, 3, 66.66666667, 4., 0., 1),
3752
(4, 1, 4, 53.33333333, 5., 0., 0), (5, 2, 0, 100., 1., 0., 0),
3753
(6, 2, 1, 200., 2., 0., 1), (7, 2, 2, 133.33333333, 3., 0., 0),
3754
(8, 2, 3, 66.66666667, 4., 0., 1), (9, 2, 4, 53.33333333, 5., 0., 0)
3755
], dtype=order_dt)
3756
)
3757
np.testing.assert_array_equal(
3758
pf.call_seq.values,
3759
np.array([
3760
[1, 0, 0],
3761
[1, 0, 0],
3762
[1, 0, 0],
3763
[1, 0, 0],
3764
[1, 0, 0]
3765
])
3766
)
3767
pf = vbt.Portfolio.from_order_func(
3768
price_wide, order_func_nb, np.asarray(np.inf), group_by=np.array([0, 0, 1]),
3769
cash_sharing=True, call_seq='random', seed=seed, row_wise=test_row_wise)
3770
if test_row_wise:
3771
record_arrays_close(
3772
pf.order_records,
3773
np.array([
3774
(0, 1, 0, 100., 1., 0., 0), (1, 2, 0, 100., 1., 0., 0),
3775
(2, 1, 1, 200., 2., 0., 1), (3, 2, 1, 200., 2., 0., 1),
3776
(4, 1, 2, 133.33333333, 3., 0., 0), (5, 2, 2, 133.33333333, 3., 0., 0),
3777
(6, 1, 3, 66.66666667, 4., 0., 1), (7, 2, 3, 66.66666667, 4., 0., 1),
3778
(8, 1, 4, 53.33333333, 5., 0., 0), (9, 2, 4, 53.33333333, 5., 0., 0)
3779
], dtype=order_dt)
3780
)
3781
else:
3782
record_arrays_close(
3783
pf.order_records,
3784
np.array([
3785
(0, 1, 0, 100., 1., 0., 0), (1, 1, 1, 200., 2., 0., 1),
3786
(2, 1, 2, 133.33333333, 3., 0., 0), (3, 1, 3, 66.66666667, 4., 0., 1),
3787
(4, 1, 4, 53.33333333, 5., 0., 0), (5, 2, 0, 100., 1., 0., 0),
3788
(6, 2, 1, 200., 2., 0., 1), (7, 2, 2, 133.33333333, 3., 0., 0),
3789
(8, 2, 3, 66.66666667, 4., 0., 1), (9, 2, 4, 53.33333333, 5., 0., 0)
3790
], dtype=order_dt)
3791
)
3792
np.testing.assert_array_equal(
3793
pf.call_seq.values,
3794
np.array([
3795
[1, 0, 0],
3796
[0, 1, 0],
3797
[1, 0, 0],
3798
[1, 0, 0],
3799
[1, 0, 0]
3800
])
3801
)
3802
with pytest.raises(Exception):
3803
_ = vbt.Portfolio.from_order_func(
3804
price_wide, order_func_nb, np.asarray(np.inf), group_by=np.array([0, 0, 1]),
3805
cash_sharing=True, call_seq='auto', row_wise=test_row_wise
3806
)
3807
3808
target_hold_value = pd.DataFrame({
3809
'a': [0., 70., 30., 0., 70.],
3810
'b': [30., 0., 70., 30., 30.],
3811
'c': [70., 30., 0., 70., 0.]
3812
}, index=price.index)
3813
3814
@njit
3815
def pre_segment_func_nb(c, target_hold_value):
3816
order_size = np.copy(target_hold_value[c.i, c.from_col:c.to_col])
3817
order_size_type = np.full(c.group_len, SizeType.TargetValue)
3818
direction = np.full(c.group_len, Direction.Both)
3819
order_value_out = np.empty(c.group_len, dtype=np.float64)
3820
c.last_val_price[c.from_col:c.to_col] = c.close[c.i, c.from_col:c.to_col]
3821
nb.sort_call_seq_nb(c, order_size, order_size_type, direction, order_value_out)
3822
return order_size, order_size_type, direction
3823
3824
@njit
3825
def pct_order_func_nb(c, order_size, order_size_type, direction):
3826
col_i = c.call_seq_now[c.call_idx]
3827
return nb.order_nb(
3828
order_size[col_i],
3829
c.close[c.i, col_i],
3830
size_type=order_size_type[col_i],
3831
direction=direction[col_i]
3832
)
3833
3834
pf = vbt.Portfolio.from_order_func(
3835
price_wide * 0 + 1, pct_order_func_nb, group_by=np.array([0, 0, 0]),
3836
cash_sharing=True, pre_segment_func_nb=pre_segment_func_nb,
3837
pre_segment_args=(target_hold_value.values,), row_wise=test_row_wise)
3838
np.testing.assert_array_equal(
3839
pf.call_seq.values,
3840
np.array([
3841
[0, 1, 2],
3842
[2, 1, 0],
3843
[0, 2, 1],
3844
[1, 0, 2],
3845
[2, 1, 0]
3846
])
3847
)
3848
pd.testing.assert_frame_equal(
3849
pf.asset_value(group_by=False),
3850
target_hold_value
3851
)
3852
3853
@pytest.mark.parametrize("test_row_wise", [False, True])
3854
@pytest.mark.parametrize("test_flexible", [False, True])
3855
def test_target_value(self, test_row_wise, test_flexible):
3856
@njit
3857
def target_val_pre_segment_func_nb(c, val_price):
3858
c.last_val_price[c.from_col:c.to_col] = val_price[c.i]
3859
return ()
3860
3861
if test_flexible:
3862
@njit
3863
def target_val_order_func_nb(c):
3864
col = c.from_col + c.call_idx
3865
if c.call_idx < c.group_len:
3866
return col, nb.order_nb(50., nb.get_col_elem_nb(c, col, c.close), size_type=SizeType.TargetValue)
3867
return -1, nb.order_nothing_nb()
3868
else:
3869
@njit
3870
def target_val_order_func_nb(c):
3871
return nb.order_nb(50., nb.get_elem_nb(c, c.close), size_type=SizeType.TargetValue)
3872
3873
pf = vbt.Portfolio.from_order_func(
3874
price.iloc[1:], target_val_order_func_nb, row_wise=test_row_wise, flexible=test_flexible)
3875
if test_row_wise:
3876
record_arrays_close(
3877
pf.order_records,
3878
np.array([
3879
(0, 0, 1, 25.0, 3.0, 0.0, 0), (1, 0, 2, 8.333333333333332, 4.0, 0.0, 1),
3880
(2, 0, 3, 4.166666666666668, 5.0, 0.0, 1)
3881
], dtype=order_dt)
3882
)
3883
else:
3884
record_arrays_close(
3885
pf.order_records,
3886
np.array([
3887
(0, 0, 1, 25.0, 3.0, 0.0, 0), (1, 0, 2, 8.333333333333332, 4.0, 0.0, 1),
3888
(2, 0, 3, 4.166666666666668, 5.0, 0.0, 1)
3889
], dtype=order_dt)
3890
)
3891
pf = vbt.Portfolio.from_order_func(
3892
price.iloc[1:], target_val_order_func_nb,
3893
pre_segment_func_nb=target_val_pre_segment_func_nb,
3894
pre_segment_args=(price.iloc[:-1].values,), row_wise=test_row_wise, flexible=test_flexible)
3895
if test_row_wise:
3896
record_arrays_close(
3897
pf.order_records,
3898
np.array([
3899
(0, 0, 0, 50.0, 2.0, 0.0, 0), (1, 0, 1, 25.0, 3.0, 0.0, 1),
3900
(2, 0, 2, 8.333333333333332, 4.0, 0.0, 1), (3, 0, 3, 4.166666666666668, 5.0, 0.0, 1)
3901
], dtype=order_dt)
3902
)
3903
else:
3904
record_arrays_close(
3905
pf.order_records,
3906
np.array([
3907
(0, 0, 0, 50.0, 2.0, 0.0, 0), (1, 0, 1, 25.0, 3.0, 0.0, 1),
3908
(2, 0, 2, 8.333333333333332, 4.0, 0.0, 1), (3, 0, 3, 4.166666666666668, 5.0, 0.0, 1)
3909
], dtype=order_dt)
3910
)
3911
3912
@pytest.mark.parametrize("test_row_wise", [False, True])
3913
@pytest.mark.parametrize("test_flexible", [False, True])
3914
def test_target_percent(self, test_row_wise, test_flexible):
3915
@njit
3916
def target_pct_pre_segment_func_nb(c, val_price):
3917
c.last_val_price[c.from_col:c.to_col] = val_price[c.i]
3918
return ()
3919
3920
if test_flexible:
3921
@njit
3922
def target_pct_order_func_nb(c):
3923
col = c.from_col + c.call_idx
3924
if c.call_idx < c.group_len:
3925
return col, nb.order_nb(0.5, nb.get_col_elem_nb(c, col, c.close), size_type=SizeType.TargetPercent)
3926
return -1, nb.order_nothing_nb()
3927
else:
3928
@njit
3929
def target_pct_order_func_nb(c):
3930
return nb.order_nb(0.5, nb.get_elem_nb(c, c.close), size_type=SizeType.TargetPercent)
3931
3932
pf = vbt.Portfolio.from_order_func(
3933
price.iloc[1:], target_pct_order_func_nb, row_wise=test_row_wise, flexible=test_flexible)
3934
if test_row_wise:
3935
record_arrays_close(
3936
pf.order_records,
3937
np.array([
3938
(0, 0, 1, 25.0, 3.0, 0.0, 0), (1, 0, 2, 8.333333333333332, 4.0, 0.0, 1),
3939
(2, 0, 3, 1.0416666666666679, 5.0, 0.0, 1)
3940
], dtype=order_dt)
3941
)
3942
else:
3943
record_arrays_close(
3944
pf.order_records,
3945
np.array([
3946
(0, 0, 1, 25.0, 3.0, 0.0, 0), (1, 0, 2, 8.333333333333332, 4.0, 0.0, 1),
3947
(2, 0, 3, 1.0416666666666679, 5.0, 0.0, 1)
3948
], dtype=order_dt)
3949
)
3950
pf = vbt.Portfolio.from_order_func(
3951
price.iloc[1:], target_pct_order_func_nb,
3952
pre_segment_func_nb=target_pct_pre_segment_func_nb,
3953
pre_segment_args=(price.iloc[:-1].values,), row_wise=test_row_wise, flexible=test_flexible)
3954
if test_row_wise:
3955
record_arrays_close(
3956
pf.order_records,
3957
np.array([
3958
(0, 0, 0, 50.0, 2.0, 0.0, 0), (1, 0, 1, 25.0, 3.0, 0.0, 1),
3959
(2, 0, 3, 3.125, 5.0, 0.0, 1)
3960
], dtype=order_dt)
3961
)
3962
else:
3963
record_arrays_close(
3964
pf.order_records,
3965
np.array([
3966
(0, 0, 0, 50.0, 2.0, 0.0, 0), (1, 0, 1, 25.0, 3.0, 0.0, 1),
3967
(2, 0, 3, 3.125, 5.0, 0.0, 1)
3968
], dtype=order_dt)
3969
)
3970
3971
@pytest.mark.parametrize("test_row_wise", [False, True])
3972
@pytest.mark.parametrize("test_flexible", [False, True])
3973
def test_update_value(self, test_row_wise, test_flexible):
3974
if test_flexible:
3975
@njit
3976
def order_func_nb(c):
3977
col = c.from_col + c.call_idx
3978
if c.call_idx < c.group_len:
3979
return col, nb.order_nb(
3980
np.inf if c.i % 2 == 0 else -np.inf,
3981
nb.get_col_elem_nb(c, col, c.close),
3982
fees=0.01,
3983
fixed_fees=1.,
3984
slippage=0.01
3985
)
3986
return -1, nb.order_nothing_nb()
3987
else:
3988
@njit
3989
def order_func_nb(c):
3990
return nb.order_nb(
3991
np.inf if c.i % 2 == 0 else -np.inf,
3992
nb.get_elem_nb(c, c.close),
3993
fees=0.01,
3994
fixed_fees=1.,
3995
slippage=0.01
3996
)
3997
3998
@njit
3999
def post_order_func_nb(c, value_before, value_now):
4000
value_before[c.i, c.col] = c.value_before
4001
value_now[c.i, c.col] = c.value_now
4002
4003
value_before = np.empty_like(price.values[:, None])
4004
value_now = np.empty_like(price.values[:, None])
4005
4006
_ = vbt.Portfolio.from_order_func(
4007
price,
4008
order_func_nb,
4009
post_order_func_nb=post_order_func_nb,
4010
post_order_args=(value_before, value_now),
4011
row_wise=test_row_wise,
4012
update_value=False,
4013
flexible=test_flexible)
4014
4015
np.testing.assert_array_equal(
4016
value_before,
4017
value_now
4018
)
4019
4020
_ = vbt.Portfolio.from_order_func(
4021
price,
4022
order_func_nb,
4023
post_order_func_nb=post_order_func_nb,
4024
post_order_args=(value_before, value_now),
4025
row_wise=test_row_wise,
4026
update_value=True,
4027
flexible=test_flexible)
4028
4029
np.testing.assert_array_equal(
4030
value_before,
4031
np.array([
4032
[100.0],
4033
[97.04930889128518],
4034
[185.46988117104038],
4035
[82.47853456223025],
4036
[104.65775576218027]
4037
])
4038
)
4039
np.testing.assert_array_equal(
4040
value_now,
4041
np.array([
4042
[98.01980198019803],
4043
[187.36243097890815],
4044
[83.30331990785257],
4045
[105.72569204546781],
4046
[73.54075125567473]
4047
])
4048
)
4049
4050
@pytest.mark.parametrize("test_row_wise", [False, True])
4051
@pytest.mark.parametrize("test_flexible", [False, True])
4052
def test_states(self, test_row_wise, test_flexible):
4053
close = np.array([
4054
[1, 1, 1],
4055
[np.nan, 2, 2],
4056
[3, np.nan, 3],
4057
[4, 4, np.nan],
4058
[5, 5, 5]
4059
])
4060
size = np.array([
4061
[1, 1, 1],
4062
[-1, -1, -1],
4063
[1, 1, 1],
4064
[-1, -1, -1],
4065
[1, 1, 1]
4066
])
4067
value_arr1 = np.empty((size.shape[0], 2), dtype=np.float64)
4068
value_arr2 = np.empty(size.shape, dtype=np.float64)
4069
value_arr3 = np.empty(size.shape, dtype=np.float64)
4070
return_arr1 = np.empty((size.shape[0], 2), dtype=np.float64)
4071
return_arr2 = np.empty(size.shape, dtype=np.float64)
4072
return_arr3 = np.empty(size.shape, dtype=np.float64)
4073
pos_record_arr1 = np.empty(size.shape, dtype=trade_dt)
4074
pos_record_arr2 = np.empty(size.shape, dtype=trade_dt)
4075
pos_record_arr3 = np.empty(size.shape, dtype=trade_dt)
4076
4077
def pre_segment_func_nb(c):
4078
value_arr1[c.i, c.group] = c.last_value[c.group]
4079
return_arr1[c.i, c.group] = c.last_return[c.group]
4080
for col in range(c.from_col, c.to_col):
4081
pos_record_arr1[c.i, col] = c.last_pos_record[col]
4082
if c.i > 0:
4083
c.last_val_price[c.from_col:c.to_col] = c.last_val_price[c.from_col:c.to_col] + 0.5
4084
return ()
4085
4086
if test_flexible:
4087
def order_func_nb(c):
4088
col = c.from_col + c.call_idx
4089
if c.call_idx < c.group_len:
4090
value_arr2[c.i, col] = c.last_value[c.group]
4091
return_arr2[c.i, col] = c.last_return[c.group]
4092
pos_record_arr2[c.i, col] = c.last_pos_record[col]
4093
return col, nb.order_nb(size[c.i, col], fixed_fees=1.)
4094
return -1, nb.order_nothing_nb()
4095
else:
4096
def order_func_nb(c):
4097
value_arr2[c.i, c.col] = c.value_now
4098
return_arr2[c.i, c.col] = c.return_now
4099
pos_record_arr2[c.i, c.col] = c.pos_record_now
4100
return nb.order_nb(size[c.i, c.col], fixed_fees=1.)
4101
4102
def post_order_func_nb(c):
4103
value_arr3[c.i, c.col] = c.value_now
4104
return_arr3[c.i, c.col] = c.return_now
4105
pos_record_arr3[c.i, c.col] = c.pos_record_now
4106
4107
_ = vbt.Portfolio.from_order_func(
4108
close,
4109
order_func_nb,
4110
pre_segment_func_nb=pre_segment_func_nb,
4111
post_order_func_nb=post_order_func_nb,
4112
use_numba=False,
4113
row_wise=test_row_wise,
4114
update_value=True,
4115
ffill_val_price=True,
4116
group_by=[0, 0, 1],
4117
cash_sharing=True,
4118
flexible=test_flexible
4119
)
4120
4121
np.testing.assert_array_equal(
4122
value_arr1,
4123
np.array([
4124
[100.0, 100.0],
4125
[98.0, 99.0],
4126
[98.5, 99.0],
4127
[99.0, 98.0],
4128
[99.0, 98.5]
4129
])
4130
)
4131
np.testing.assert_array_equal(
4132
value_arr2,
4133
np.array([
4134
[100.0, 99.0, 100.0],
4135
[99.0, 99.0, 99.5],
4136
[99.0, 99.0, 99.0],
4137
[100.0, 100.0, 98.5],
4138
[99.0, 98.5, 99.0]
4139
])
4140
)
4141
np.testing.assert_array_equal(
4142
value_arr3,
4143
np.array([
4144
[99.0, 98.0, 99.0],
4145
[99.0, 98.5, 99.0],
4146
[99.0, 99.0, 98.0],
4147
[100.0, 99.0, 98.5],
4148
[98.5, 97.0, 99.0]
4149
])
4150
)
4151
np.testing.assert_array_equal(
4152
return_arr1,
4153
np.array([
4154
[np.nan, np.nan],
4155
[-0.02, -0.01],
4156
[0.00510204081632653, 0.0],
4157
[0.005076142131979695, -0.010101010101010102],
4158
[0.0, 0.00510204081632653]
4159
])
4160
)
4161
np.testing.assert_array_equal(
4162
return_arr2,
4163
np.array([
4164
[0.0, -0.01, 0.0],
4165
[-0.01, -0.01, -0.005],
4166
[0.01020408163265306, 0.01020408163265306, 0.0],
4167
[0.015228426395939087, 0.015228426395939087, -0.005050505050505051],
4168
[0.0, -0.005050505050505051, 0.01020408163265306]
4169
])
4170
)
4171
np.testing.assert_array_equal(
4172
return_arr3,
4173
np.array([
4174
[-0.01, -0.02, -0.01],
4175
[-0.01, -0.015, -0.01],
4176
[0.01020408163265306, 0.01020408163265306, -0.010101010101010102],
4177
[0.015228426395939087, 0.005076142131979695, -0.005050505050505051],
4178
[-0.005050505050505051, -0.020202020202020204, 0.01020408163265306]
4179
])
4180
)
4181
record_arrays_close(
4182
pos_record_arr1.flatten()[3:],
4183
np.array([
4184
(0, 0, 1.0, 0, 1.0, 1.0, -1, np.nan, 0.0, -1.0, -1.0, 0, 0, 0),
4185
(0, 1, 1.0, 0, 1.0, 1.0, -1, np.nan, 0.0, -1.0, -1.0, 0, 0, 0),
4186
(0, 2, 1.0, 0, 1.0, 1.0, -1, np.nan, 0.0, -1.0, -1.0, 0, 0, 0),
4187
(0, 0, 1.0, 0, 1.0, 1.0, -1, np.nan, 0.0, -0.5, -0.5, 0, 0, 0),
4188
(0, 1, 1.0, 0, 1.0, 1.0, 1, 2.0, 1.0, -1.0, -1.0, 0, 1, 0),
4189
(0, 2, 1.0, 0, 1.0, 1.0, 1, 2.0, 1.0, -1.0, -1.0, 0, 1, 0),
4190
(0, 0, 2.0, 0, 2.0, 2.0, -1, np.nan, 0.0, 0.0, 0.0, 0, 0, 0),
4191
(0, 1, 1.0, 0, 1.0, 1.0, 1, 2.0, 1.0, -1.0, -1.0, 0, 1, 0),
4192
(1, 2, 1.0, 2, 3.0, 1.0, -1, np.nan, 0.0, -1.0, -0.3333333333333333, 0, 0, 1),
4193
(0, 0, 2.0, 0, 2.0, 2.0, -1, 4.0, 1.0, 1.0, 0.25, 0, 0, 0),
4194
(1, 1, 1.0, 3, 4.0, 1.0, -1, np.nan, 0.0, -1.0, -0.25, 1, 0, 1),
4195
(1, 2, 1.0, 2, 3.0, 1.0, -1, np.nan, 0.0, -0.5, -0.16666666666666666, 0, 0, 1)
4196
], dtype=trade_dt)
4197
)
4198
record_arrays_close(
4199
pos_record_arr2.flatten()[3:],
4200
np.array([
4201
(0, 0, 1.0, 0, 1.0, 1.0, -1, np.nan, 0.0, -0.5, -0.5, 0, 0, 0),
4202
(0, 1, 1.0, 0, 1.0, 1.0, -1, np.nan, 0.0, -0.5, -0.5, 0, 0, 0),
4203
(0, 2, 1.0, 0, 1.0, 1.0, -1, np.nan, 0.0, -0.5, -0.5, 0, 0, 0),
4204
(0, 0, 1.0, 0, 1.0, 1.0, -1, np.nan, 0.0, 0.0, 0.0, 0, 0, 0),
4205
(0, 1, 1.0, 0, 1.0, 1.0, 1, 2.0, 1.0, -1.0, -1.0, 0, 1, 0),
4206
(0, 2, 1.0, 0, 1.0, 1.0, 1, 2.0, 1.0, -1.0, -1.0, 0, 1, 0),
4207
(0, 0, 2.0, 0, 2.0, 2.0, -1, np.nan, 0.0, 1.0, 0.25, 0, 0, 0),
4208
(0, 1, 1.0, 0, 1.0, 1.0, 1, 2.0, 1.0, -1.0, -1.0, 0, 1, 0),
4209
(1, 2, 1.0, 2, 3.0, 1.0, -1, np.nan, 0.0, -0.5, -0.16666666666666666, 0, 0, 1),
4210
(0, 0, 2.0, 0, 2.0, 2.0, -1, 4.0, 1.0, 1.5, 0.375, 0, 0, 0),
4211
(1, 1, 1.0, 3, 4.0, 1.0, -1, np.nan, 0.0, -1.5, -0.375, 1, 0, 1),
4212
(1, 2, 1.0, 2, 3.0, 1.0, -1, np.nan, 0.0, 0.0, 0.0, 0, 0, 1)
4213
], dtype=trade_dt)
4214
)
4215
record_arrays_close(
4216
pos_record_arr3.flatten(),
4217
np.array([
4218
(0, 0, 1.0, 0, 1.0, 1.0, -1, np.nan, 0.0, -1.0, -1.0, 0, 0, 0),
4219
(0, 1, 1.0, 0, 1.0, 1.0, -1, np.nan, 0.0, -1.0, -1.0, 0, 0, 0),
4220
(0, 2, 1.0, 0, 1.0, 1.0, -1, np.nan, 0.0, -1.0, -1.0, 0, 0, 0),
4221
(0, 0, 1.0, 0, 1.0, 1.0, -1, np.nan, 0.0, -0.5, -0.5, 0, 0, 0),
4222
(0, 1, 1.0, 0, 1.0, 1.0, 1, 2.0, 1.0, -1.0, -1.0, 0, 1, 0),
4223
(0, 2, 1.0, 0, 1.0, 1.0, 1, 2.0, 1.0, -1.0, -1.0, 0, 1, 0),
4224
(0, 0, 2.0, 0, 2.0, 2.0, -1, np.nan, 0.0, 0.0, 0.0, 0, 0, 0),
4225
(0, 1, 1.0, 0, 1.0, 1.0, 1, 2.0, 1.0, -1.0, -1.0, 0, 1, 0),
4226
(1, 2, 1.0, 2, 3.0, 1.0, -1, np.nan, 0.0, -1.0, -0.3333333333333333, 0, 0, 1),
4227
(0, 0, 2.0, 0, 2.0, 2.0, -1, 4.0, 1.0, 1.0, 0.25, 0, 0, 0),
4228
(1, 1, 1.0, 3, 4.0, 1.0, -1, np.nan, 0.0, -1.0, -0.25, 1, 0, 1),
4229
(1, 2, 1.0, 2, 3.0, 1.0, -1, np.nan, 0.0, -0.5, -0.16666666666666666, 0, 0, 1),
4230
(0, 0, 3.0, 0, 3.0, 3.0, -1, 4.0, 1.0, 1.0, 0.1111111111111111, 0, 0, 0),
4231
(1, 1, 1.0, 3, 4.0, 1.0, 4, 5.0, 1.0, -3.0, -0.75, 1, 1, 1),
4232
(1, 2, 2.0, 2, 4.0, 2.0, -1, np.nan, 0.0, 0.0, 0.0, 0, 0, 1)
4233
], dtype=trade_dt)
4234
)
4235
4236
cash_arr = np.empty((size.shape[0], 2), dtype=np.float64)
4237
position_arr = np.empty(size.shape, dtype=np.float64)
4238
val_price_arr = np.empty(size.shape, dtype=np.float64)
4239
value_arr = np.empty((size.shape[0], 2), dtype=np.float64)
4240
return_arr = np.empty((size.shape[0], 2), dtype=np.float64)
4241
sim_order_cash_arr = np.empty(size.shape, dtype=np.float64)
4242
sim_order_value_arr = np.empty(size.shape, dtype=np.float64)
4243
sim_order_return_arr = np.empty(size.shape, dtype=np.float64)
4244
4245
def post_order_func_nb(c):
4246
sim_order_cash_arr[c.i, c.col] = c.cash_now
4247
sim_order_value_arr[c.i, c.col] = c.value_now
4248
sim_order_return_arr[c.i, c.col] = c.value_now
4249
if c.i == 0 and c.call_idx == 0:
4250
sim_order_return_arr[c.i, c.col] -= c.init_cash[c.group]
4251
sim_order_return_arr[c.i, c.col] /= c.init_cash[c.group]
4252
else:
4253
if c.call_idx == 0:
4254
prev_i = c.i - 1
4255
prev_col = c.to_col - 1
4256
else:
4257
prev_i = c.i
4258
prev_col = c.from_col + c.call_idx - 1
4259
sim_order_return_arr[c.i, c.col] -= sim_order_value_arr[prev_i, prev_col]
4260
sim_order_return_arr[c.i, c.col] /= sim_order_value_arr[prev_i, prev_col]
4261
4262
def post_segment_func_nb(c):
4263
cash_arr[c.i, c.group] = c.last_cash[c.group]
4264
for col in range(c.from_col, c.to_col):
4265
position_arr[c.i, col] = c.last_position[col]
4266
val_price_arr[c.i, col] = c.last_val_price[col]
4267
value_arr[c.i, c.group] = c.last_value[c.group]
4268
return_arr[c.i, c.group] = c.last_return[c.group]
4269
4270
pf = vbt.Portfolio.from_order_func(
4271
close,
4272
order_func_nb,
4273
post_order_func_nb=post_order_func_nb,
4274
post_segment_func_nb=post_segment_func_nb,
4275
use_numba=False,
4276
row_wise=test_row_wise,
4277
update_value=True,
4278
ffill_val_price=True,
4279
group_by=[0, 0, 1],
4280
cash_sharing=True,
4281
flexible=test_flexible
4282
)
4283
4284
np.testing.assert_array_equal(
4285
cash_arr,
4286
pf.cash().values
4287
)
4288
np.testing.assert_array_equal(
4289
position_arr,
4290
pf.assets().values
4291
)
4292
np.testing.assert_array_equal(
4293
val_price_arr,
4294
pf.get_filled_close().values
4295
)
4296
np.testing.assert_array_equal(
4297
value_arr,
4298
pf.value().values
4299
)
4300
np.testing.assert_array_equal(
4301
return_arr,
4302
pf.returns().values
4303
)
4304
if test_flexible:
4305
with pytest.raises(Exception):
4306
pf.cash(in_sim_order=True, group_by=False)
4307
with pytest.raises(Exception):
4308
pf.value(in_sim_order=True, group_by=False)
4309
with pytest.raises(Exception):
4310
pf.returns(in_sim_order=True, group_by=False)
4311
else:
4312
np.testing.assert_array_equal(
4313
sim_order_cash_arr,
4314
pf.cash(in_sim_order=True, group_by=False).values
4315
)
4316
np.testing.assert_array_equal(
4317
sim_order_value_arr,
4318
pf.value(in_sim_order=True, group_by=False).values
4319
)
4320
np.testing.assert_array_equal(
4321
sim_order_return_arr,
4322
pf.returns(in_sim_order=True, group_by=False).values
4323
)
4324
4325
@pytest.mark.parametrize("test_row_wise", [False, True])
4326
@pytest.mark.parametrize("test_flexible", [False, True])
4327
def test_post_sim_ctx(self, test_row_wise, test_flexible):
4328
if test_flexible:
4329
def order_func(c):
4330
col = c.from_col + c.call_idx
4331
if c.call_idx < c.group_len:
4332
return col, nb.order_nb(
4333
1.,
4334
nb.get_col_elem_nb(c, col, c.close),
4335
fees=0.01,
4336
fixed_fees=1.,
4337
slippage=0.01,
4338
log=True
4339
)
4340
return -1, nb.order_nothing_nb()
4341
else:
4342
def order_func(c):
4343
return nb.order_nb(
4344
1.,
4345
nb.get_elem_nb(c, c.close),
4346
fees=0.01,
4347
fixed_fees=1.,
4348
slippage=0.01,
4349
log=True
4350
)
4351
4352
def post_sim_func(c, lst):
4353
lst.append(deepcopy(c))
4354
4355
lst = []
4356
4357
_ = vbt.Portfolio.from_order_func(
4358
price_wide,
4359
order_func,
4360
post_sim_func_nb=post_sim_func,
4361
post_sim_args=(lst,),
4362
row_wise=test_row_wise,
4363
update_value=True,
4364
max_logs=price_wide.shape[0] * price_wide.shape[1],
4365
use_numba=False,
4366
group_by=[0, 0, 1],
4367
cash_sharing=True,
4368
flexible=test_flexible
4369
)
4370
4371
c = lst[-1]
4372
4373
assert c.target_shape == price_wide.shape
4374
np.testing.assert_array_equal(
4375
c.close,
4376
price_wide.values
4377
)
4378
np.testing.assert_array_equal(
4379
c.group_lens,
4380
np.array([2, 1])
4381
)
4382
np.testing.assert_array_equal(
4383
c.init_cash,
4384
np.array([100., 100.])
4385
)
4386
assert c.cash_sharing
4387
if test_flexible:
4388
assert c.call_seq is None
4389
else:
4390
np.testing.assert_array_equal(
4391
c.call_seq,
4392
np.array([
4393
[0, 1, 0],
4394
[0, 1, 0],
4395
[0, 1, 0],
4396
[0, 1, 0],
4397
[0, 1, 0]
4398
])
4399
)
4400
np.testing.assert_array_equal(
4401
c.segment_mask,
4402
np.array([
4403
[True, True],
4404
[True, True],
4405
[True, True],
4406
[True, True],
4407
[True, True]
4408
])
4409
)
4410
assert c.ffill_val_price
4411
assert c.update_value
4412
if test_row_wise:
4413
record_arrays_close(
4414
c.order_records,
4415
np.array([
4416
(0, 0, 0, 1.0, 1.01, 1.0101, 0), (1, 1, 0, 1.0, 1.01, 1.0101, 0),
4417
(2, 2, 0, 1.0, 1.01, 1.0101, 0), (3, 0, 1, 1.0, 2.02, 1.0202, 0),
4418
(4, 1, 1, 1.0, 2.02, 1.0202, 0), (5, 2, 1, 1.0, 2.02, 1.0202, 0),
4419
(6, 0, 2, 1.0, 3.0300000000000002, 1.0303, 0), (7, 1, 2, 1.0, 3.0300000000000002, 1.0303, 0),
4420
(8, 2, 2, 1.0, 3.0300000000000002, 1.0303, 0), (9, 0, 3, 1.0, 4.04, 1.0404, 0),
4421
(10, 1, 3, 1.0, 4.04, 1.0404, 0), (11, 2, 3, 1.0, 4.04, 1.0404, 0),
4422
(12, 0, 4, 1.0, 5.05, 1.0505, 0), (13, 1, 4, 1.0, 5.05, 1.0505, 0),
4423
(14, 2, 4, 1.0, 5.05, 1.0505, 0)
4424
], dtype=order_dt)
4425
)
4426
else:
4427
record_arrays_close(
4428
c.order_records,
4429
np.array([
4430
(0, 0, 0, 1.0, 1.01, 1.0101, 0), (1, 1, 0, 1.0, 1.01, 1.0101, 0),
4431
(2, 0, 1, 1.0, 2.02, 1.0202, 0), (3, 1, 1, 1.0, 2.02, 1.0202, 0),
4432
(4, 0, 2, 1.0, 3.0300000000000002, 1.0303, 0), (5, 1, 2, 1.0, 3.0300000000000002, 1.0303, 0),
4433
(6, 0, 3, 1.0, 4.04, 1.0404, 0), (7, 1, 3, 1.0, 4.04, 1.0404, 0),
4434
(8, 0, 4, 1.0, 5.05, 1.0505, 0), (9, 1, 4, 1.0, 5.05, 1.0505, 0),
4435
(10, 2, 0, 1.0, 1.01, 1.0101, 0), (11, 2, 1, 1.0, 2.02, 1.0202, 0),
4436
(12, 2, 2, 1.0, 3.0300000000000002, 1.0303, 0), (13, 2, 3, 1.0, 4.04, 1.0404, 0),
4437
(14, 2, 4, 1.0, 5.05, 1.0505, 0)
4438
], dtype=order_dt)
4439
)
4440
if test_row_wise:
4441
record_arrays_close(
4442
c.log_records,
4443
np.array([
4444
(0, 0, 0, 0, 100.0, 0.0, 0.0, 100.0, np.nan, 100.0, 1.0, 1.0, 0, 2, 0.01, 1.0, 0.01,
4445
0.0, np.inf, np.nan, 0.0, False, True, False, True, 97.9799, 1.0, 0.0, 97.9799, 1.01,
4446
98.9899, 1.0, 1.01, 1.0101, 0, 0, -1, 0),
4447
(1, 0, 1, 0, 97.9799, 0.0, 0.0, 97.9799, np.nan, 98.9899, 1.0, 1.0, 0, 2, 0.01,
4448
1.0, 0.01, 0.0, np.inf, np.nan, 0.0, False, True, False, True, 95.9598, 1.0, 0.0,
4449
95.9598, 1.01, 97.97980000000001, 1.0, 1.01, 1.0101, 0, 0, -1, 1),
4450
(2, 1, 2, 0, 100.0, 0.0, 0.0, 100.0, np.nan, 100.0, 1.0, 1.0, 0, 2, 0.01, 1.0, 0.01,
4451
0.0, np.inf, np.nan, 0.0, False, True, False, True, 97.9799, 1.0, 0.0, 97.9799, 1.01,
4452
98.9899, 1.0, 1.01, 1.0101, 0, 0, -1, 2),
4453
(3, 0, 0, 1, 95.9598, 1.0, 0.0, 95.9598, 1.0, 97.9598, 1.0, 2.0, 0, 2, 0.01,
4454
1.0, 0.01, 0.0, np.inf, np.nan, 0.0, False, True, False, True, 92.9196, 2.0, 0.0,
4455
92.9196, 2.02, 97.95960000000001, 1.0, 2.02, 1.0202, 0, 0, -1, 3),
4456
(4, 0, 1, 1, 92.9196, 1.0, 0.0, 92.9196, 1.0, 97.95960000000001, 1.0, 2.0,
4457
0, 2, 0.01, 1.0, 0.01, 0.0, np.inf, np.nan, 0.0, False, True, False, True,
4458
89.8794, 2.0, 0.0, 89.8794, 2.02, 97.95940000000002, 1.0, 2.02, 1.0202, 0, 0, -1, 4),
4459
(5, 1, 2, 1, 97.9799, 1.0, 0.0, 97.9799, 1.0, 98.9799, 1.0, 2.0, 0, 2, 0.01,
4460
1.0, 0.01, 0.0, np.inf, np.nan, 0.0, False, True, False, True, 94.9397, 2.0, 0.0,
4461
94.9397, 2.02, 98.97970000000001, 1.0, 2.02, 1.0202, 0, 0, -1, 5),
4462
(6, 0, 0, 2, 89.8794, 2.0, 0.0, 89.8794, 2.0, 97.8794, 1.0, 3.0, 0, 2, 0.01,
4463
1.0, 0.01, 0.0, np.inf, np.nan, 0.0, False, True, False, True, 85.8191, 3.0, 0.0,
4464
85.8191, 3.0300000000000002, 98.90910000000001, 1.0, 3.0300000000000002, 1.0303, 0, 0, -1, 6),
4465
(7, 0, 1, 2, 85.8191, 2.0, 0.0, 85.8191, 2.0, 98.90910000000001, 1.0, 3.0, 0,
4466
2, 0.01, 1.0, 0.01, 0.0, np.inf, np.nan, 0.0, False, True, False, True,
4467
81.75880000000001, 3.0, 0.0, 81.75880000000001, 3.0300000000000002, 99.93880000000001,
4468
1.0, 3.0300000000000002, 1.0303, 0, 0, -1, 7),
4469
(8, 1, 2, 2, 94.9397, 2.0, 0.0, 94.9397, 2.0, 98.9397, 1.0, 3.0, 0, 2, 0.01,
4470
1.0, 0.01, 0.0, np.inf, np.nan, 0.0, False, True, False, True, 90.8794, 3.0, 0.0,
4471
90.8794, 3.0300000000000002, 99.96940000000001, 1.0, 3.0300000000000002, 1.0303, 0, 0, -1, 8),
4472
(9, 0, 0, 3, 81.75880000000001, 3.0, 0.0, 81.75880000000001, 3.0, 99.75880000000001,
4473
1.0, 4.0, 0, 2, 0.01, 1.0, 0.01, 0.0, np.inf, np.nan, 0.0, False, True, False, True,
4474
76.67840000000001, 4.0, 0.0, 76.67840000000001, 4.04, 101.83840000000001, 1.0,
4475
4.04, 1.0404, 0, 0, -1, 9),
4476
(10, 0, 1, 3, 76.67840000000001, 3.0, 0.0, 76.67840000000001, 3.0, 101.83840000000001,
4477
1.0, 4.0, 0, 2, 0.01, 1.0, 0.01, 0.0, np.inf, np.nan, 0.0, False, True, False, True,
4478
71.59800000000001, 4.0, 0.0, 71.59800000000001, 4.04, 103.918, 1.0, 4.04, 1.0404,
4479
0, 0, -1, 10),
4480
(11, 1, 2, 3, 90.8794, 3.0, 0.0, 90.8794, 3.0, 99.8794, 1.0, 4.0, 0, 2, 0.01,
4481
1.0, 0.01, 0.0, np.inf, np.nan, 0.0, False, True, False, True, 85.799, 4.0, 0.0, 85.799,
4482
4.04, 101.959, 1.0, 4.04, 1.0404, 0, 0, -1, 11),
4483
(12, 0, 0, 4, 71.59800000000001, 4.0, 0.0, 71.59800000000001, 4.0, 103.59800000000001,
4484
1.0, 5.0, 0, 2, 0.01, 1.0, 0.01, 0.0, np.inf, np.nan, 0.0, False, True, False, True,
4485
65.49750000000002, 5.0, 0.0, 65.49750000000002, 5.05, 106.74750000000002, 1.0,
4486
5.05, 1.0505, 0, 0, -1, 12),
4487
(13, 0, 1, 4, 65.49750000000002, 4.0, 0.0, 65.49750000000002, 4.0, 106.74750000000002,
4488
1.0, 5.0, 0, 2, 0.01, 1.0, 0.01, 0.0, np.inf, np.nan, 0.0, False, True, False, True,
4489
59.39700000000002, 5.0, 0.0, 59.39700000000002, 5.05, 109.89700000000002, 1.0,
4490
5.05, 1.0505, 0, 0, -1, 13),
4491
(14, 1, 2, 4, 85.799, 4.0, 0.0, 85.799, 4.0, 101.799, 1.0, 5.0, 0, 2, 0.01, 1.0,
4492
0.01, 0.0, np.inf, np.nan, 0.0, False, True, False, True, 79.69850000000001, 5.0, 0.0,
4493
79.69850000000001, 5.05, 104.94850000000001, 1.0, 5.05, 1.0505, 0, 0, -1, 14)
4494
], dtype=log_dt)
4495
)
4496
else:
4497
record_arrays_close(
4498
c.log_records,
4499
np.array([
4500
(0, 0, 0, 0, 100.0, 0.0, 0.0, 100.0, np.nan, 100.0, 1.0, 1.0, 0, 2, 0.01, 1.0, 0.01,
4501
0.0, np.inf, np.nan, 0.0, False, True, False, True, 97.9799, 1.0, 0.0, 97.9799, 1.01,
4502
98.9899, 1.0, 1.01, 1.0101, 0, 0, -1, 0),
4503
(1, 0, 1, 0, 97.9799, 0.0, 0.0, 97.9799, np.nan, 98.9899, 1.0, 1.0, 0, 2, 0.01, 1.0,
4504
0.01, 0.0, np.inf, np.nan, 0.0, False, True, False, True, 95.9598, 1.0, 0.0, 95.9598,
4505
1.01, 97.97980000000001, 1.0, 1.01, 1.0101, 0, 0, -1, 1),
4506
(2, 0, 0, 1, 95.9598, 1.0, 0.0, 95.9598, 1.0, 97.9598, 1.0, 2.0, 0, 2, 0.01, 1.0,
4507
0.01, 0.0, np.inf, np.nan, 0.0, False, True, False, True, 92.9196, 2.0, 0.0, 92.9196,
4508
2.02, 97.95960000000001, 1.0, 2.02, 1.0202, 0, 0, -1, 2),
4509
(3, 0, 1, 1, 92.9196, 1.0, 0.0, 92.9196, 1.0, 97.95960000000001, 1.0, 2.0, 0, 2,
4510
0.01, 1.0, 0.01, 0.0, np.inf, np.nan, 0.0, False, True, False, True, 89.8794, 2.0, 0.0,
4511
89.8794, 2.02, 97.95940000000002, 1.0, 2.02, 1.0202, 0, 0, -1, 3),
4512
(4, 0, 0, 2, 89.8794, 2.0, 0.0, 89.8794, 2.0, 97.8794, 1.0, 3.0, 0, 2, 0.01, 1.0,
4513
0.01, 0.0, np.inf, np.nan, 0.0, False, True, False, True, 85.8191, 3.0, 0.0, 85.8191,
4514
3.0300000000000002, 98.90910000000001, 1.0, 3.0300000000000002, 1.0303, 0, 0, -1, 4),
4515
(5, 0, 1, 2, 85.8191, 2.0, 0.0, 85.8191, 2.0, 98.90910000000001, 1.0, 3.0, 0, 2,
4516
0.01, 1.0, 0.01, 0.0, np.inf, np.nan, 0.0, False, True, False, True, 81.75880000000001,
4517
3.0, 0.0, 81.75880000000001, 3.0300000000000002, 99.93880000000001, 1.0,
4518
3.0300000000000002, 1.0303, 0, 0, -1, 5),
4519
(6, 0, 0, 3, 81.75880000000001, 3.0, 0.0, 81.75880000000001, 3.0, 99.75880000000001,
4520
1.0, 4.0, 0, 2, 0.01, 1.0, 0.01, 0.0, np.inf, np.nan, 0.0, False, True, False, True,
4521
76.67840000000001, 4.0, 0.0, 76.67840000000001, 4.04, 101.83840000000001, 1.0,
4522
4.04, 1.0404, 0, 0, -1, 6),
4523
(7, 0, 1, 3, 76.67840000000001, 3.0, 0.0, 76.67840000000001, 3.0, 101.83840000000001,
4524
1.0, 4.0, 0, 2, 0.01, 1.0, 0.01, 0.0, np.inf, np.nan, 0.0, False, True, False, True,
4525
71.59800000000001, 4.0, 0.0, 71.59800000000001, 4.04, 103.918, 1.0, 4.04, 1.0404, 0, 0, -1, 7),
4526
(8, 0, 0, 4, 71.59800000000001, 4.0, 0.0, 71.59800000000001, 4.0, 103.59800000000001,
4527
1.0, 5.0, 0, 2, 0.01, 1.0, 0.01, 0.0, np.inf, np.nan, 0.0, False, True, False, True,
4528
65.49750000000002, 5.0, 0.0, 65.49750000000002, 5.05, 106.74750000000002, 1.0,
4529
5.05, 1.0505, 0, 0, -1, 8),
4530
(9, 0, 1, 4, 65.49750000000002, 4.0, 0.0, 65.49750000000002, 4.0, 106.74750000000002,
4531
1.0, 5.0, 0, 2, 0.01, 1.0, 0.01, 0.0, np.inf, np.nan, 0.0, False, True, False, True,
4532
59.39700000000002, 5.0, 0.0, 59.39700000000002, 5.05, 109.89700000000002, 1.0,
4533
5.05, 1.0505, 0, 0, -1, 9),
4534
(10, 1, 2, 0, 100.0, 0.0, 0.0, 100.0, np.nan, 100.0, 1.0, 1.0, 0, 2, 0.01, 1.0, 0.01,
4535
0.0, np.inf, np.nan, 0.0, False, True, False, True, 97.9799, 1.0, 0.0, 97.9799, 1.01,
4536
98.9899, 1.0, 1.01, 1.0101, 0, 0, -1, 10),
4537
(11, 1, 2, 1, 97.9799, 1.0, 0.0, 97.9799, 1.0, 98.9799, 1.0, 2.0, 0, 2, 0.01,
4538
1.0, 0.01, 0.0, np.inf, np.nan, 0.0, False, True, False, True, 94.9397, 2.0, 0.0,
4539
94.9397, 2.02, 98.97970000000001, 1.0, 2.02, 1.0202, 0, 0, -1, 11),
4540
(12, 1, 2, 2, 94.9397, 2.0, 0.0, 94.9397, 2.0, 98.9397, 1.0, 3.0, 0, 2, 0.01,
4541
1.0, 0.01, 0.0, np.inf, np.nan, 0.0, False, True, False, True, 90.8794, 3.0, 0.0, 90.8794,
4542
3.0300000000000002, 99.96940000000001, 1.0, 3.0300000000000002, 1.0303, 0, 0, -1, 12),
4543
(13, 1, 2, 3, 90.8794, 3.0, 0.0, 90.8794, 3.0, 99.8794, 1.0, 4.0, 0, 2, 0.01, 1.0,
4544
0.01, 0.0, np.inf, np.nan, 0.0, False, True, False, True, 85.799, 4.0, 0.0, 85.799, 4.04,
4545
101.959, 1.0, 4.04, 1.0404, 0, 0, -1, 13),
4546
(14, 1, 2, 4, 85.799, 4.0, 0.0, 85.799, 4.0, 101.799, 1.0, 5.0, 0, 2, 0.01, 1.0,
4547
0.01, 0.0, np.inf, np.nan, 0.0, False, True, False, True, 79.69850000000001, 5.0, 0.0,
4548
79.69850000000001, 5.05, 104.94850000000001, 1.0, 5.05, 1.0505, 0, 0, -1, 14)
4549
], dtype=log_dt)
4550
)
4551
np.testing.assert_array_equal(
4552
c.last_cash,
4553
np.array([59.39700000000002, 79.69850000000001])
4554
)
4555
np.testing.assert_array_equal(
4556
c.last_position,
4557
np.array([5., 5., 5.])
4558
)
4559
np.testing.assert_array_equal(
4560
c.last_val_price,
4561
np.array([5.0, 5.0, 5.0])
4562
)
4563
np.testing.assert_array_equal(
4564
c.last_value,
4565
np.array([109.39700000000002, 104.69850000000001])
4566
)
4567
np.testing.assert_array_equal(
4568
c.second_last_value,
4569
np.array([103.59800000000001, 101.799])
4570
)
4571
np.testing.assert_array_equal(
4572
c.last_return,
4573
np.array([0.05597598409235705, 0.028482598060884715])
4574
)
4575
np.testing.assert_array_equal(
4576
c.last_debt,
4577
np.array([0., 0., 0.])
4578
)
4579
np.testing.assert_array_equal(
4580
c.last_free_cash,
4581
np.array([59.39700000000002, 79.69850000000001])
4582
)
4583
if test_row_wise:
4584
np.testing.assert_array_equal(
4585
c.last_oidx,
4586
np.array([12, 13, 14])
4587
)
4588
np.testing.assert_array_equal(
4589
c.last_lidx,
4590
np.array([12, 13, 14])
4591
)
4592
else:
4593
np.testing.assert_array_equal(
4594
c.last_oidx,
4595
np.array([8, 9, 14])
4596
)
4597
np.testing.assert_array_equal(
4598
c.last_lidx,
4599
np.array([8, 9, 14])
4600
)
4601
assert c.order_records[c.last_oidx[0]]['col'] == 0
4602
assert c.order_records[c.last_oidx[1]]['col'] == 1
4603
assert c.order_records[c.last_oidx[2]]['col'] == 2
4604
assert c.log_records[c.last_lidx[0]]['col'] == 0
4605
assert c.log_records[c.last_lidx[1]]['col'] == 1
4606
assert c.log_records[c.last_lidx[2]]['col'] == 2
4607
4608
@pytest.mark.parametrize("test_row_wise", [False, True])
4609
@pytest.mark.parametrize("test_flexible", [False, True])
4610
def test_free_cash(self, test_row_wise, test_flexible):
4611
if test_flexible:
4612
def order_func(c, size):
4613
col = c.from_col + c.call_idx
4614
if c.call_idx < c.group_len:
4615
return col, nb.order_nb(
4616
size[c.i, col],
4617
nb.get_col_elem_nb(c, col, c.close),
4618
fees=0.01,
4619
fixed_fees=1.,
4620
slippage=0.01
4621
)
4622
return -1, nb.order_nothing_nb()
4623
else:
4624
def order_func(c, size):
4625
return nb.order_nb(
4626
size[c.i, c.col],
4627
nb.get_elem_nb(c, c.close),
4628
fees=0.01,
4629
fixed_fees=1.,
4630
slippage=0.01
4631
)
4632
4633
def post_order_func(c, debt, free_cash):
4634
debt[c.i, c.col] = c.debt_now
4635
if c.cash_sharing:
4636
free_cash[c.i, c.group] = c.free_cash_now
4637
else:
4638
free_cash[c.i, c.col] = c.free_cash_now
4639
4640
size = np.array([
4641
[5, -5, 5],
4642
[5, -5, -10],
4643
[-5, 5, 10],
4644
[-5, 5, -10],
4645
[-5, 5, 10]
4646
])
4647
debt = np.empty(price_wide.shape, dtype=np.float64)
4648
free_cash = np.empty(price_wide.shape, dtype=np.float64)
4649
pf = vbt.Portfolio.from_order_func(
4650
price_wide,
4651
order_func, size,
4652
post_order_func_nb=post_order_func,
4653
post_order_args=(debt, free_cash,),
4654
row_wise=test_row_wise,
4655
use_numba=False,
4656
flexible=test_flexible
4657
)
4658
np.testing.assert_array_equal(
4659
debt,
4660
np.array([
4661
[0.0, 4.95, 0.0],
4662
[0.0, 14.850000000000001, 9.9],
4663
[0.0, 7.425000000000001, 0.0],
4664
[0.0, 0.0, 19.8],
4665
[24.75, 0.0, 0.0]
4666
])
4667
)
4668
np.testing.assert_array_equal(
4669
free_cash,
4670
np.array([
4671
[93.8995, 94.0005, 93.8995],
4672
[82.6985, 83.00150000000001, 92.70150000000001],
4673
[96.39999999999999, 81.55000000000001, 80.8985],
4674
[115.002, 74.998, 79.5025],
4675
[89.0045, 48.49550000000001, 67.0975]
4676
])
4677
)
4678
np.testing.assert_almost_equal(
4679
free_cash,
4680
pf.cash(free=True).values
4681
)
4682
4683
debt = np.empty(price_wide.shape, dtype=np.float64)
4684
free_cash = np.empty(price_wide.shape, dtype=np.float64)
4685
pf = vbt.Portfolio.from_order_func(
4686
price_wide.vbt.wrapper.wrap(price_wide.values[::-1]),
4687
order_func, size,
4688
post_order_func_nb=post_order_func,
4689
post_order_args=(debt, free_cash,),
4690
row_wise=test_row_wise,
4691
use_numba=False,
4692
flexible=test_flexible
4693
)
4694
np.testing.assert_array_equal(
4695
debt,
4696
np.array([
4697
[0.0, 24.75, 0.0],
4698
[0.0, 44.55, 19.8],
4699
[0.0, 22.275, 0.0],
4700
[0.0, 0.0, 9.9],
4701
[4.95, 0.0, 0.0]
4702
])
4703
)
4704
np.testing.assert_array_equal(
4705
free_cash,
4706
np.array([
4707
[73.4975, 74.0025, 73.4975],
4708
[52.0955, 53.00449999999999, 72.1015],
4709
[65.797, 81.25299999999999, 80.0985],
4710
[74.598, 114.60199999999998, 78.9005],
4711
[68.5985, 108.50149999999998, 87.49949999999998]
4712
])
4713
)
4714
np.testing.assert_almost_equal(
4715
free_cash,
4716
pf.cash(free=True).values
4717
)
4718
4719
debt = np.empty(price_wide.shape, dtype=np.float64)
4720
free_cash = np.empty((price_wide.shape[0], 2), dtype=np.float64)
4721
pf = vbt.Portfolio.from_order_func(
4722
price_wide,
4723
order_func, size,
4724
post_order_func_nb=post_order_func,
4725
post_order_args=(debt, free_cash,),
4726
row_wise=test_row_wise,
4727
use_numba=False,
4728
group_by=[0, 0, 1],
4729
cash_sharing=True,
4730
flexible=test_flexible
4731
)
4732
np.testing.assert_array_equal(
4733
debt,
4734
np.array([
4735
[0.0, 4.95, 0.0],
4736
[0.0, 14.850000000000001, 9.9],
4737
[0.0, 7.425000000000001, 0.0],
4738
[0.0, 0.0, 19.8],
4739
[24.75, 0.0, 0.0]
4740
])
4741
)
4742
np.testing.assert_array_equal(
4743
free_cash,
4744
np.array([
4745
[87.9, 93.8995],
4746
[65.70000000000002, 92.70150000000001],
4747
[77.95000000000002, 80.8985],
4748
[90.00000000000001, 79.5025],
4749
[37.500000000000014, 67.0975]
4750
])
4751
)
4752
np.testing.assert_almost_equal(
4753
free_cash,
4754
pf.cash(free=True).values
4755
)
4756
4757
@pytest.mark.parametrize("test_row_wise", [False, True])
4758
@pytest.mark.parametrize("test_flexible", [False, True])
4759
def test_init_cash(self, test_row_wise, test_flexible):
4760
order_func = flex_order_func_nb if test_flexible else order_func_nb
4761
pf = vbt.Portfolio.from_order_func(
4762
price_wide, order_func, np.asarray(10.), row_wise=test_row_wise,
4763
init_cash=[1., 10., np.inf], flexible=test_flexible)
4764
if test_row_wise:
4765
record_arrays_close(
4766
pf.order_records,
4767
np.array([
4768
(0, 0, 0, 1.0, 1.0, 0.0, 0), (1, 1, 0, 10.0, 1.0, 0.0, 0),
4769
(2, 2, 0, 10.0, 1.0, 0.0, 0), (3, 0, 1, 10.0, 2.0, 0.0, 1),
4770
(4, 1, 1, 10.0, 2.0, 0.0, 1), (5, 2, 1, 10.0, 2.0, 0.0, 1),
4771
(6, 0, 2, 6.666666666666667, 3.0, 0.0, 0), (7, 1, 2, 6.666666666666667, 3.0, 0.0, 0),
4772
(8, 2, 2, 10.0, 3.0, 0.0, 0), (9, 0, 3, 10.0, 4.0, 0.0, 1),
4773
(10, 1, 3, 10.0, 4.0, 0.0, 1), (11, 2, 3, 10.0, 4.0, 0.0, 1),
4774
(12, 0, 4, 8.0, 5.0, 0.0, 0), (13, 1, 4, 8.0, 5.0, 0.0, 0),
4775
(14, 2, 4, 10.0, 5.0, 0.0, 0)
4776
], dtype=order_dt)
4777
)
4778
else:
4779
record_arrays_close(
4780
pf.order_records,
4781
np.array([
4782
(0, 0, 0, 1.0, 1.0, 0.0, 0), (1, 0, 1, 10.0, 2.0, 0.0, 1),
4783
(2, 0, 2, 6.666666666666667, 3.0, 0.0, 0), (3, 0, 3, 10.0, 4.0, 0.0, 1),
4784
(4, 0, 4, 8.0, 5.0, 0.0, 0), (5, 1, 0, 10.0, 1.0, 0.0, 0),
4785
(6, 1, 1, 10.0, 2.0, 0.0, 1), (7, 1, 2, 6.666666666666667, 3.0, 0.0, 0),
4786
(8, 1, 3, 10.0, 4.0, 0.0, 1), (9, 1, 4, 8.0, 5.0, 0.0, 0),
4787
(10, 2, 0, 10.0, 1.0, 0.0, 0), (11, 2, 1, 10.0, 2.0, 0.0, 1),
4788
(12, 2, 2, 10.0, 3.0, 0.0, 0), (13, 2, 3, 10.0, 4.0, 0.0, 1),
4789
(14, 2, 4, 10.0, 5.0, 0.0, 0)
4790
], dtype=order_dt)
4791
)
4792
assert type(pf._init_cash) == np.ndarray
4793
base_pf = vbt.Portfolio.from_order_func(
4794
price_wide, order_func, np.asarray(10.), row_wise=test_row_wise,
4795
init_cash=np.inf, flexible=test_flexible)
4796
pf = vbt.Portfolio.from_order_func(
4797
price_wide, order_func, np.asarray(10.), row_wise=test_row_wise,
4798
init_cash=InitCashMode.Auto, flexible=test_flexible)
4799
record_arrays_close(
4800
pf.order_records,
4801
base_pf.orders.values
4802
)
4803
assert pf._init_cash == InitCashMode.Auto
4804
pf = vbt.Portfolio.from_order_func(
4805
price_wide, order_func, np.asarray(10.), row_wise=test_row_wise,
4806
init_cash=InitCashMode.AutoAlign, flexible=test_flexible)
4807
record_arrays_close(
4808
pf.order_records,
4809
base_pf.orders.values
4810
)
4811
assert pf._init_cash == InitCashMode.AutoAlign
4812
4813
def test_func_calls(self):
4814
@njit
4815
def pre_sim_func_nb(c, call_i, pre_sim_lst, sub_arg):
4816
if sub_arg != 15:
4817
raise ValueError
4818
call_i[0] += 1
4819
pre_sim_lst.append(call_i[0])
4820
return (call_i,)
4821
4822
@njit
4823
def post_sim_func_nb(c, call_i, post_sim_lst, sub_arg):
4824
if sub_arg != 15:
4825
raise ValueError
4826
call_i[0] += 1
4827
post_sim_lst.append(call_i[0])
4828
return (call_i,)
4829
4830
@njit
4831
def pre_group_func_nb(c, call_i, pre_group_lst, sub_arg):
4832
if sub_arg != 15:
4833
raise ValueError
4834
call_i[0] += 1
4835
pre_group_lst.append(call_i[0])
4836
return (call_i,)
4837
4838
@njit
4839
def post_group_func_nb(c, call_i, post_group_lst, sub_arg):
4840
if sub_arg != 15:
4841
raise ValueError
4842
call_i[0] += 1
4843
post_group_lst.append(call_i[0])
4844
return (call_i,)
4845
4846
@njit
4847
def pre_segment_func_nb(c, call_i, pre_segment_lst, sub_arg):
4848
if sub_arg != 15:
4849
raise ValueError
4850
call_i[0] += 1
4851
pre_segment_lst.append(call_i[0])
4852
return (call_i,)
4853
4854
@njit
4855
def post_segment_func_nb(c, call_i, post_segment_lst, sub_arg):
4856
if sub_arg != 15:
4857
raise ValueError
4858
call_i[0] += 1
4859
post_segment_lst.append(call_i[0])
4860
return (call_i,)
4861
4862
@njit
4863
def order_func_nb(c, call_i, order_lst, sub_arg):
4864
if sub_arg != 15:
4865
raise ValueError
4866
call_i[0] += 1
4867
order_lst.append(call_i[0])
4868
return NoOrder
4869
4870
@njit
4871
def post_order_func_nb(c, call_i, post_order_lst, sub_arg):
4872
if sub_arg != 15:
4873
raise ValueError
4874
call_i[0] += 1
4875
post_order_lst.append(call_i[0])
4876
4877
sub_arg = vbt.RepEval('np.prod([target_shape[0], target_shape[1]])')
4878
4879
call_i = np.array([0])
4880
pre_sim_lst = List.empty_list(typeof(0))
4881
post_sim_lst = List.empty_list(typeof(0))
4882
pre_group_lst = List.empty_list(typeof(0))
4883
post_group_lst = List.empty_list(typeof(0))
4884
pre_segment_lst = List.empty_list(typeof(0))
4885
post_segment_lst = List.empty_list(typeof(0))
4886
order_lst = List.empty_list(typeof(0))
4887
post_order_lst = List.empty_list(typeof(0))
4888
_ = vbt.Portfolio.from_order_func(
4889
price_wide, order_func_nb, order_lst, sub_arg,
4890
group_by=np.array([0, 0, 1]),
4891
pre_sim_func_nb=pre_sim_func_nb, pre_sim_args=(call_i, pre_sim_lst, sub_arg),
4892
post_sim_func_nb=post_sim_func_nb, post_sim_args=(call_i, post_sim_lst, sub_arg),
4893
pre_group_func_nb=pre_group_func_nb, pre_group_args=(pre_group_lst, sub_arg),
4894
post_group_func_nb=post_group_func_nb, post_group_args=(post_group_lst, sub_arg),
4895
pre_segment_func_nb=pre_segment_func_nb, pre_segment_args=(pre_segment_lst, sub_arg),
4896
post_segment_func_nb=post_segment_func_nb, post_segment_args=(post_segment_lst, sub_arg),
4897
post_order_func_nb=post_order_func_nb, post_order_args=(post_order_lst, sub_arg),
4898
row_wise=False, template_mapping=dict(np=np)
4899
)
4900
assert call_i[0] == 56
4901
assert list(pre_sim_lst) == [1]
4902
assert list(post_sim_lst) == [56]
4903
assert list(pre_group_lst) == [2, 34]
4904
assert list(post_group_lst) == [33, 55]
4905
assert list(pre_segment_lst) == [3, 9, 15, 21, 27, 35, 39, 43, 47, 51]
4906
assert list(post_segment_lst) == [8, 14, 20, 26, 32, 38, 42, 46, 50, 54]
4907
assert list(order_lst) == [4, 6, 10, 12, 16, 18, 22, 24, 28, 30, 36, 40, 44, 48, 52]
4908
assert list(post_order_lst) == [5, 7, 11, 13, 17, 19, 23, 25, 29, 31, 37, 41, 45, 49, 53]
4909
4910
segment_mask = np.array([
4911
[False, False],
4912
[False, True],
4913
[True, False],
4914
[True, True],
4915
[False, False],
4916
])
4917
call_i = np.array([0])
4918
pre_sim_lst = List.empty_list(typeof(0))
4919
post_sim_lst = List.empty_list(typeof(0))
4920
pre_group_lst = List.empty_list(typeof(0))
4921
post_group_lst = List.empty_list(typeof(0))
4922
pre_segment_lst = List.empty_list(typeof(0))
4923
post_segment_lst = List.empty_list(typeof(0))
4924
order_lst = List.empty_list(typeof(0))
4925
post_order_lst = List.empty_list(typeof(0))
4926
_ = vbt.Portfolio.from_order_func(
4927
price_wide, order_func_nb, order_lst, sub_arg,
4928
group_by=np.array([0, 0, 1]),
4929
pre_sim_func_nb=pre_sim_func_nb, pre_sim_args=(call_i, pre_sim_lst, sub_arg),
4930
post_sim_func_nb=post_sim_func_nb, post_sim_args=(call_i, post_sim_lst, sub_arg),
4931
pre_group_func_nb=pre_group_func_nb, pre_group_args=(pre_group_lst, sub_arg),
4932
post_group_func_nb=post_group_func_nb, post_group_args=(post_group_lst, sub_arg),
4933
pre_segment_func_nb=pre_segment_func_nb, pre_segment_args=(pre_segment_lst, sub_arg),
4934
post_segment_func_nb=post_segment_func_nb, post_segment_args=(post_segment_lst, sub_arg),
4935
post_order_func_nb=post_order_func_nb, post_order_args=(post_order_lst, sub_arg),
4936
segment_mask=segment_mask, call_pre_segment=True, call_post_segment=True,
4937
row_wise=False, template_mapping=dict(np=np)
4938
)
4939
assert call_i[0] == 38
4940
assert list(pre_sim_lst) == [1]
4941
assert list(post_sim_lst) == [38]
4942
assert list(pre_group_lst) == [2, 22]
4943
assert list(post_group_lst) == [21, 37]
4944
assert list(pre_segment_lst) == [3, 5, 7, 13, 19, 23, 25, 29, 31, 35]
4945
assert list(post_segment_lst) == [4, 6, 12, 18, 20, 24, 28, 30, 34, 36]
4946
assert list(order_lst) == [8, 10, 14, 16, 26, 32]
4947
assert list(post_order_lst) == [9, 11, 15, 17, 27, 33]
4948
4949
call_i = np.array([0])
4950
pre_sim_lst = List.empty_list(typeof(0))
4951
post_sim_lst = List.empty_list(typeof(0))
4952
pre_group_lst = List.empty_list(typeof(0))
4953
post_group_lst = List.empty_list(typeof(0))
4954
pre_segment_lst = List.empty_list(typeof(0))
4955
post_segment_lst = List.empty_list(typeof(0))
4956
order_lst = List.empty_list(typeof(0))
4957
post_order_lst = List.empty_list(typeof(0))
4958
_ = vbt.Portfolio.from_order_func(
4959
price_wide, order_func_nb, order_lst, sub_arg,
4960
group_by=np.array([0, 0, 1]),
4961
pre_sim_func_nb=pre_sim_func_nb, pre_sim_args=(call_i, pre_sim_lst, sub_arg),
4962
post_sim_func_nb=post_sim_func_nb, post_sim_args=(call_i, post_sim_lst, sub_arg),
4963
pre_group_func_nb=pre_group_func_nb, pre_group_args=(pre_group_lst, sub_arg),
4964
post_group_func_nb=post_group_func_nb, post_group_args=(post_group_lst, sub_arg),
4965
pre_segment_func_nb=pre_segment_func_nb, pre_segment_args=(pre_segment_lst, sub_arg),
4966
post_segment_func_nb=post_segment_func_nb, post_segment_args=(post_segment_lst, sub_arg),
4967
post_order_func_nb=post_order_func_nb, post_order_args=(post_order_lst, sub_arg),
4968
segment_mask=segment_mask, call_pre_segment=False, call_post_segment=False,
4969
row_wise=False, template_mapping=dict(np=np)
4970
)
4971
assert call_i[0] == 26
4972
assert list(pre_sim_lst) == [1]
4973
assert list(post_sim_lst) == [26]
4974
assert list(pre_group_lst) == [2, 16]
4975
assert list(post_group_lst) == [15, 25]
4976
assert list(pre_segment_lst) == [3, 9, 17, 21]
4977
assert list(post_segment_lst) == [8, 14, 20, 24]
4978
assert list(order_lst) == [4, 6, 10, 12, 18, 22]
4979
assert list(post_order_lst) == [5, 7, 11, 13, 19, 23]
4980
4981
def test_func_calls_flexible(self):
4982
@njit
4983
def pre_sim_func_nb(c, call_i, pre_sim_lst, sub_arg):
4984
if sub_arg != 15:
4985
raise ValueError
4986
call_i[0] += 1
4987
pre_sim_lst.append(call_i[0])
4988
return (call_i,)
4989
4990
@njit
4991
def post_sim_func_nb(c, call_i, post_sim_lst, sub_arg):
4992
if sub_arg != 15:
4993
raise ValueError
4994
call_i[0] += 1
4995
post_sim_lst.append(call_i[0])
4996
return (call_i,)
4997
4998
@njit
4999
def pre_group_func_nb(c, call_i, pre_group_lst, sub_arg):
5000
if sub_arg != 15:
5001
raise ValueError
5002
call_i[0] += 1
5003
pre_group_lst.append(call_i[0])
5004
return (call_i,)
5005
5006
@njit
5007
def post_group_func_nb(c, call_i, post_group_lst, sub_arg):
5008
if sub_arg != 15:
5009
raise ValueError
5010
call_i[0] += 1
5011
post_group_lst.append(call_i[0])
5012
return (call_i,)
5013
5014
@njit
5015
def pre_segment_func_nb(c, call_i, pre_segment_lst, sub_arg):
5016
if sub_arg != 15:
5017
raise ValueError
5018
call_i[0] += 1
5019
pre_segment_lst.append(call_i[0])
5020
return (call_i,)
5021
5022
@njit
5023
def post_segment_func_nb(c, call_i, post_segment_lst, sub_arg):
5024
if sub_arg != 15:
5025
raise ValueError
5026
call_i[0] += 1
5027
post_segment_lst.append(call_i[0])
5028
return (call_i,)
5029
5030
@njit
5031
def flex_order_func_nb(c, call_i, order_lst, sub_arg):
5032
if sub_arg != 15:
5033
raise ValueError
5034
call_i[0] += 1
5035
order_lst.append(call_i[0])
5036
col = c.from_col + c.call_idx
5037
if c.call_idx < c.group_len:
5038
return col, NoOrder
5039
return -1, NoOrder
5040
5041
@njit
5042
def post_order_func_nb(c, call_i, post_order_lst, sub_arg):
5043
if sub_arg != 15:
5044
raise ValueError
5045
call_i[0] += 1
5046
post_order_lst.append(call_i[0])
5047
5048
sub_arg = vbt.RepEval('np.prod([target_shape[0], target_shape[1]])')
5049
5050
call_i = np.array([0])
5051
pre_sim_lst = List.empty_list(typeof(0))
5052
post_sim_lst = List.empty_list(typeof(0))
5053
pre_group_lst = List.empty_list(typeof(0))
5054
post_group_lst = List.empty_list(typeof(0))
5055
pre_segment_lst = List.empty_list(typeof(0))
5056
post_segment_lst = List.empty_list(typeof(0))
5057
order_lst = List.empty_list(typeof(0))
5058
post_order_lst = List.empty_list(typeof(0))
5059
_ = vbt.Portfolio.from_order_func(
5060
price_wide, flex_order_func_nb, order_lst, sub_arg,
5061
group_by=np.array([0, 0, 1]),
5062
pre_sim_func_nb=pre_sim_func_nb, pre_sim_args=(call_i, pre_sim_lst, sub_arg),
5063
post_sim_func_nb=post_sim_func_nb, post_sim_args=(call_i, post_sim_lst, sub_arg),
5064
pre_group_func_nb=pre_group_func_nb, pre_group_args=(pre_group_lst, sub_arg),
5065
post_group_func_nb=post_group_func_nb, post_group_args=(post_group_lst, sub_arg),
5066
pre_segment_func_nb=pre_segment_func_nb, pre_segment_args=(pre_segment_lst, sub_arg),
5067
post_segment_func_nb=post_segment_func_nb, post_segment_args=(post_segment_lst, sub_arg),
5068
post_order_func_nb=post_order_func_nb, post_order_args=(post_order_lst, sub_arg),
5069
row_wise=False, flexible=True, template_mapping=dict(np=np)
5070
)
5071
assert call_i[0] == 66
5072
assert list(pre_sim_lst) == [1]
5073
assert list(post_sim_lst) == [66]
5074
assert list(pre_group_lst) == [2, 39]
5075
assert list(post_group_lst) == [38, 65]
5076
assert list(pre_segment_lst) == [3, 10, 17, 24, 31, 40, 45, 50, 55, 60]
5077
assert list(post_segment_lst) == [9, 16, 23, 30, 37, 44, 49, 54, 59, 64]
5078
assert list(order_lst) == [
5079
4, 6, 8, 11, 13, 15, 18, 20, 22, 25, 27, 29, 32, 34,
5080
36, 41, 43, 46, 48, 51, 53, 56, 58, 61, 63
5081
]
5082
assert list(post_order_lst) == [5, 7, 12, 14, 19, 21, 26, 28, 33, 35, 42, 47, 52, 57, 62]
5083
5084
segment_mask = np.array([
5085
[False, False],
5086
[False, True],
5087
[True, False],
5088
[True, True],
5089
[False, False],
5090
])
5091
call_i = np.array([0])
5092
pre_sim_lst = List.empty_list(typeof(0))
5093
post_sim_lst = List.empty_list(typeof(0))
5094
pre_group_lst = List.empty_list(typeof(0))
5095
post_group_lst = List.empty_list(typeof(0))
5096
pre_segment_lst = List.empty_list(typeof(0))
5097
post_segment_lst = List.empty_list(typeof(0))
5098
order_lst = List.empty_list(typeof(0))
5099
post_order_lst = List.empty_list(typeof(0))
5100
_ = vbt.Portfolio.from_order_func(
5101
price_wide, flex_order_func_nb, order_lst, sub_arg,
5102
group_by=np.array([0, 0, 1]),
5103
pre_sim_func_nb=pre_sim_func_nb, pre_sim_args=(call_i, pre_sim_lst, sub_arg),
5104
post_sim_func_nb=post_sim_func_nb, post_sim_args=(call_i, post_sim_lst, sub_arg),
5105
pre_group_func_nb=pre_group_func_nb, pre_group_args=(pre_group_lst, sub_arg),
5106
post_group_func_nb=post_group_func_nb, post_group_args=(post_group_lst, sub_arg),
5107
pre_segment_func_nb=pre_segment_func_nb, pre_segment_args=(pre_segment_lst, sub_arg),
5108
post_segment_func_nb=post_segment_func_nb, post_segment_args=(post_segment_lst, sub_arg),
5109
post_order_func_nb=post_order_func_nb, post_order_args=(post_order_lst, sub_arg),
5110
segment_mask=segment_mask, call_pre_segment=True, call_post_segment=True,
5111
row_wise=False, flexible=True, template_mapping=dict(np=np)
5112
)
5113
assert call_i[0] == 42
5114
assert list(pre_sim_lst) == [1]
5115
assert list(post_sim_lst) == [42]
5116
assert list(pre_group_lst) == [2, 24]
5117
assert list(post_group_lst) == [23, 41]
5118
assert list(pre_segment_lst) == [3, 5, 7, 14, 21, 25, 27, 32, 34, 39]
5119
assert list(post_segment_lst) == [4, 6, 13, 20, 22, 26, 31, 33, 38, 40]
5120
assert list(order_lst) == [8, 10, 12, 15, 17, 19, 28, 30, 35, 37]
5121
assert list(post_order_lst) == [9, 11, 16, 18, 29, 36]
5122
5123
call_i = np.array([0])
5124
pre_sim_lst = List.empty_list(typeof(0))
5125
post_sim_lst = List.empty_list(typeof(0))
5126
pre_group_lst = List.empty_list(typeof(0))
5127
post_group_lst = List.empty_list(typeof(0))
5128
pre_segment_lst = List.empty_list(typeof(0))
5129
post_segment_lst = List.empty_list(typeof(0))
5130
order_lst = List.empty_list(typeof(0))
5131
post_order_lst = List.empty_list(typeof(0))
5132
_ = vbt.Portfolio.from_order_func(
5133
price_wide, flex_order_func_nb, order_lst, sub_arg,
5134
group_by=np.array([0, 0, 1]),
5135
pre_sim_func_nb=pre_sim_func_nb, pre_sim_args=(call_i, pre_sim_lst, sub_arg),
5136
post_sim_func_nb=post_sim_func_nb, post_sim_args=(call_i, post_sim_lst, sub_arg),
5137
pre_group_func_nb=pre_group_func_nb, pre_group_args=(pre_group_lst, sub_arg),
5138
post_group_func_nb=post_group_func_nb, post_group_args=(post_group_lst, sub_arg),
5139
pre_segment_func_nb=pre_segment_func_nb, pre_segment_args=(pre_segment_lst, sub_arg),
5140
post_segment_func_nb=post_segment_func_nb, post_segment_args=(post_segment_lst, sub_arg),
5141
post_order_func_nb=post_order_func_nb, post_order_args=(post_order_lst, sub_arg),
5142
segment_mask=segment_mask, call_pre_segment=False, call_post_segment=False,
5143
row_wise=False, flexible=True, template_mapping=dict(np=np)
5144
)
5145
assert call_i[0] == 30
5146
assert list(pre_sim_lst) == [1]
5147
assert list(post_sim_lst) == [30]
5148
assert list(pre_group_lst) == [2, 18]
5149
assert list(post_group_lst) == [17, 29]
5150
assert list(pre_segment_lst) == [3, 10, 19, 24]
5151
assert list(post_segment_lst) == [9, 16, 23, 28]
5152
assert list(order_lst) == [4, 6, 8, 11, 13, 15, 20, 22, 25, 27]
5153
assert list(post_order_lst) == [5, 7, 12, 14, 21, 26]
5154
5155
def test_func_calls_row_wise(self):
5156
@njit
5157
def pre_sim_func_nb(c, call_i, pre_sim_lst):
5158
call_i[0] += 1
5159
pre_sim_lst.append(call_i[0])
5160
return (call_i,)
5161
5162
@njit
5163
def post_sim_func_nb(c, call_i, post_sim_lst):
5164
call_i[0] += 1
5165
post_sim_lst.append(call_i[0])
5166
return (call_i,)
5167
5168
@njit
5169
def pre_row_func_nb(c, call_i, pre_row_lst):
5170
call_i[0] += 1
5171
pre_row_lst.append(call_i[0])
5172
return (call_i,)
5173
5174
@njit
5175
def post_row_func_nb(c, call_i, post_row_lst):
5176
call_i[0] += 1
5177
post_row_lst.append(call_i[0])
5178
return (call_i,)
5179
5180
@njit
5181
def pre_segment_func_nb(c, call_i, pre_segment_lst):
5182
call_i[0] += 1
5183
pre_segment_lst.append(call_i[0])
5184
return (call_i,)
5185
5186
@njit
5187
def post_segment_func_nb(c, call_i, post_segment_lst):
5188
call_i[0] += 1
5189
post_segment_lst.append(call_i[0])
5190
return (call_i,)
5191
5192
@njit
5193
def order_func_nb(c, call_i, order_lst):
5194
call_i[0] += 1
5195
order_lst.append(call_i[0])
5196
return NoOrder
5197
5198
@njit
5199
def post_order_func_nb(c, call_i, post_order_lst):
5200
call_i[0] += 1
5201
post_order_lst.append(call_i[0])
5202
5203
sub_arg = vbt.RepEval('np.prod([target_shape[0], target_shape[1]])')
5204
5205
call_i = np.array([0])
5206
pre_sim_lst = List.empty_list(typeof(0))
5207
post_sim_lst = List.empty_list(typeof(0))
5208
pre_row_lst = List.empty_list(typeof(0))
5209
post_row_lst = List.empty_list(typeof(0))
5210
pre_segment_lst = List.empty_list(typeof(0))
5211
post_segment_lst = List.empty_list(typeof(0))
5212
order_lst = List.empty_list(typeof(0))
5213
post_order_lst = List.empty_list(typeof(0))
5214
_ = vbt.Portfolio.from_order_func(
5215
price_wide, order_func_nb, order_lst,
5216
group_by=np.array([0, 0, 1]),
5217
pre_sim_func_nb=pre_sim_func_nb, pre_sim_args=(call_i, pre_sim_lst),
5218
post_sim_func_nb=post_sim_func_nb, post_sim_args=(call_i, post_sim_lst),
5219
pre_row_func_nb=pre_row_func_nb, pre_row_args=(pre_row_lst,),
5220
post_row_func_nb=post_row_func_nb, post_row_args=(post_row_lst,),
5221
pre_segment_func_nb=pre_segment_func_nb, pre_segment_args=(pre_segment_lst,),
5222
post_segment_func_nb=post_segment_func_nb, post_segment_args=(post_segment_lst,),
5223
post_order_func_nb=post_order_func_nb, post_order_args=(post_order_lst,),
5224
row_wise=True, template_mapping=dict(np=np)
5225
)
5226
assert call_i[0] == 62
5227
assert list(pre_sim_lst) == [1]
5228
assert list(post_sim_lst) == [62]
5229
assert list(pre_row_lst) == [2, 14, 26, 38, 50]
5230
assert list(post_row_lst) == [13, 25, 37, 49, 61]
5231
assert list(pre_segment_lst) == [3, 9, 15, 21, 27, 33, 39, 45, 51, 57]
5232
assert list(post_segment_lst) == [8, 12, 20, 24, 32, 36, 44, 48, 56, 60]
5233
assert list(order_lst) == [4, 6, 10, 16, 18, 22, 28, 30, 34, 40, 42, 46, 52, 54, 58]
5234
assert list(post_order_lst) == [5, 7, 11, 17, 19, 23, 29, 31, 35, 41, 43, 47, 53, 55, 59]
5235
5236
segment_mask = np.array([
5237
[False, False],
5238
[False, True],
5239
[True, False],
5240
[True, True],
5241
[False, False],
5242
])
5243
call_i = np.array([0])
5244
pre_sim_lst = List.empty_list(typeof(0))
5245
post_sim_lst = List.empty_list(typeof(0))
5246
pre_row_lst = List.empty_list(typeof(0))
5247
post_row_lst = List.empty_list(typeof(0))
5248
pre_segment_lst = List.empty_list(typeof(0))
5249
post_segment_lst = List.empty_list(typeof(0))
5250
order_lst = List.empty_list(typeof(0))
5251
post_order_lst = List.empty_list(typeof(0))
5252
_ = vbt.Portfolio.from_order_func(
5253
price_wide, order_func_nb, order_lst,
5254
group_by=np.array([0, 0, 1]),
5255
pre_sim_func_nb=pre_sim_func_nb, pre_sim_args=(call_i, pre_sim_lst),
5256
post_sim_func_nb=post_sim_func_nb, post_sim_args=(call_i, post_sim_lst),
5257
pre_row_func_nb=pre_row_func_nb, pre_row_args=(pre_row_lst,),
5258
post_row_func_nb=post_row_func_nb, post_row_args=(post_row_lst,),
5259
pre_segment_func_nb=pre_segment_func_nb, pre_segment_args=(pre_segment_lst,),
5260
post_segment_func_nb=post_segment_func_nb, post_segment_args=(post_segment_lst,),
5261
post_order_func_nb=post_order_func_nb, post_order_args=(post_order_lst,),
5262
segment_mask=segment_mask, call_pre_segment=True, call_post_segment=True,
5263
row_wise=True, template_mapping=dict(np=np)
5264
)
5265
assert call_i[0] == 44
5266
assert list(pre_sim_lst) == [1]
5267
assert list(post_sim_lst) == [44]
5268
assert list(pre_row_lst) == [2, 8, 16, 26, 38]
5269
assert list(post_row_lst) == [7, 15, 25, 37, 43]
5270
assert list(pre_segment_lst) == [3, 5, 9, 11, 17, 23, 27, 33, 39, 41]
5271
assert list(post_segment_lst) == [4, 6, 10, 14, 22, 24, 32, 36, 40, 42]
5272
assert list(order_lst) == [12, 18, 20, 28, 30, 34]
5273
assert list(post_order_lst) == [13, 19, 21, 29, 31, 35]
5274
5275
call_i = np.array([0])
5276
pre_sim_lst = List.empty_list(typeof(0))
5277
post_sim_lst = List.empty_list(typeof(0))
5278
pre_row_lst = List.empty_list(typeof(0))
5279
post_row_lst = List.empty_list(typeof(0))
5280
pre_segment_lst = List.empty_list(typeof(0))
5281
post_segment_lst = List.empty_list(typeof(0))
5282
order_lst = List.empty_list(typeof(0))
5283
post_order_lst = List.empty_list(typeof(0))
5284
_ = vbt.Portfolio.from_order_func(
5285
price_wide, order_func_nb, order_lst,
5286
group_by=np.array([0, 0, 1]),
5287
pre_sim_func_nb=pre_sim_func_nb, pre_sim_args=(call_i, pre_sim_lst),
5288
post_sim_func_nb=post_sim_func_nb, post_sim_args=(call_i, post_sim_lst),
5289
pre_row_func_nb=pre_row_func_nb, pre_row_args=(pre_row_lst,),
5290
post_row_func_nb=post_row_func_nb, post_row_args=(post_row_lst,),
5291
pre_segment_func_nb=pre_segment_func_nb, pre_segment_args=(pre_segment_lst,),
5292
post_segment_func_nb=post_segment_func_nb, post_segment_args=(post_segment_lst,),
5293
post_order_func_nb=post_order_func_nb, post_order_args=(post_order_lst,),
5294
segment_mask=segment_mask, call_pre_segment=False, call_post_segment=False,
5295
row_wise=True, template_mapping=dict(np=np)
5296
)
5297
assert call_i[0] == 32
5298
assert list(pre_sim_lst) == [1]
5299
assert list(post_sim_lst) == [32]
5300
assert list(pre_row_lst) == [2, 4, 10, 18, 30]
5301
assert list(post_row_lst) == [3, 9, 17, 29, 31]
5302
assert list(pre_segment_lst) == [5, 11, 19, 25]
5303
assert list(post_segment_lst) == [8, 16, 24, 28]
5304
assert list(order_lst) == [6, 12, 14, 20, 22, 26]
5305
assert list(post_order_lst) == [7, 13, 15, 21, 23, 27]
5306
5307
def test_func_calls_row_wise_flexible(self):
5308
@njit
5309
def pre_sim_func_nb(c, call_i, pre_sim_lst, sub_arg):
5310
if sub_arg != 15:
5311
raise ValueError
5312
call_i[0] += 1
5313
pre_sim_lst.append(call_i[0])
5314
return (call_i,)
5315
5316
@njit
5317
def post_sim_func_nb(c, call_i, post_sim_lst, sub_arg):
5318
if sub_arg != 15:
5319
raise ValueError
5320
call_i[0] += 1
5321
post_sim_lst.append(call_i[0])
5322
return (call_i,)
5323
5324
@njit
5325
def pre_row_func_nb(c, call_i, pre_row_lst, sub_arg):
5326
if sub_arg != 15:
5327
raise ValueError
5328
call_i[0] += 1
5329
pre_row_lst.append(call_i[0])
5330
return (call_i,)
5331
5332
@njit
5333
def post_row_func_nb(c, call_i, post_row_lst, sub_arg):
5334
if sub_arg != 15:
5335
raise ValueError
5336
call_i[0] += 1
5337
post_row_lst.append(call_i[0])
5338
return (call_i,)
5339
5340
@njit
5341
def pre_segment_func_nb(c, call_i, pre_segment_lst, sub_arg):
5342
if sub_arg != 15:
5343
raise ValueError
5344
call_i[0] += 1
5345
pre_segment_lst.append(call_i[0])
5346
return (call_i,)
5347
5348
@njit
5349
def post_segment_func_nb(c, call_i, post_segment_lst, sub_arg):
5350
if sub_arg != 15:
5351
raise ValueError
5352
call_i[0] += 1
5353
post_segment_lst.append(call_i[0])
5354
return (call_i,)
5355
5356
@njit
5357
def flex_order_func_nb(c, call_i, order_lst, sub_arg):
5358
if sub_arg != 15:
5359
raise ValueError
5360
call_i[0] += 1
5361
order_lst.append(call_i[0])
5362
col = c.from_col + c.call_idx
5363
if c.call_idx < c.group_len:
5364
return col, NoOrder
5365
return -1, NoOrder
5366
5367
@njit
5368
def post_order_func_nb(c, call_i, post_order_lst, sub_arg):
5369
if sub_arg != 15:
5370
raise ValueError
5371
call_i[0] += 1
5372
post_order_lst.append(call_i[0])
5373
5374
sub_arg = vbt.RepEval('np.prod([target_shape[0], target_shape[1]])')
5375
5376
call_i = np.array([0])
5377
pre_sim_lst = List.empty_list(typeof(0))
5378
post_sim_lst = List.empty_list(typeof(0))
5379
pre_row_lst = List.empty_list(typeof(0))
5380
post_row_lst = List.empty_list(typeof(0))
5381
pre_segment_lst = List.empty_list(typeof(0))
5382
post_segment_lst = List.empty_list(typeof(0))
5383
order_lst = List.empty_list(typeof(0))
5384
post_order_lst = List.empty_list(typeof(0))
5385
_ = vbt.Portfolio.from_order_func(
5386
price_wide, flex_order_func_nb, order_lst, sub_arg,
5387
group_by=np.array([0, 0, 1]),
5388
pre_sim_func_nb=pre_sim_func_nb, pre_sim_args=(call_i, pre_sim_lst, sub_arg),
5389
post_sim_func_nb=post_sim_func_nb, post_sim_args=(call_i, post_sim_lst, sub_arg),
5390
pre_row_func_nb=pre_row_func_nb, pre_row_args=(pre_row_lst, sub_arg),
5391
post_row_func_nb=post_row_func_nb, post_row_args=(post_row_lst, sub_arg),
5392
pre_segment_func_nb=pre_segment_func_nb, pre_segment_args=(pre_segment_lst, sub_arg),
5393
post_segment_func_nb=post_segment_func_nb, post_segment_args=(post_segment_lst, sub_arg),
5394
post_order_func_nb=post_order_func_nb, post_order_args=(post_order_lst, sub_arg),
5395
row_wise=True, flexible=True, template_mapping=dict(np=np)
5396
)
5397
assert call_i[0] == 72
5398
assert list(pre_sim_lst) == [1]
5399
assert list(post_sim_lst) == [72]
5400
assert list(pre_row_lst) == [2, 16, 30, 44, 58]
5401
assert list(post_row_lst) == [15, 29, 43, 57, 71]
5402
assert list(pre_segment_lst) == [3, 10, 17, 24, 31, 38, 45, 52, 59, 66]
5403
assert list(post_segment_lst) == [9, 14, 23, 28, 37, 42, 51, 56, 65, 70]
5404
assert list(order_lst) == [
5405
4, 6, 8, 11, 13, 18, 20, 22, 25, 27, 32, 34, 36,
5406
39, 41, 46, 48, 50, 53, 55, 60, 62, 64, 67, 69
5407
]
5408
assert list(post_order_lst) == [5, 7, 12, 19, 21, 26, 33, 35, 40, 47, 49, 54, 61, 63, 68]
5409
5410
segment_mask = np.array([
5411
[False, False],
5412
[False, True],
5413
[True, False],
5414
[True, True],
5415
[False, False],
5416
])
5417
call_i = np.array([0])
5418
pre_sim_lst = List.empty_list(typeof(0))
5419
post_sim_lst = List.empty_list(typeof(0))
5420
pre_row_lst = List.empty_list(typeof(0))
5421
post_row_lst = List.empty_list(typeof(0))
5422
pre_segment_lst = List.empty_list(typeof(0))
5423
post_segment_lst = List.empty_list(typeof(0))
5424
order_lst = List.empty_list(typeof(0))
5425
post_order_lst = List.empty_list(typeof(0))
5426
_ = vbt.Portfolio.from_order_func(
5427
price_wide, flex_order_func_nb, order_lst, sub_arg,
5428
group_by=np.array([0, 0, 1]),
5429
pre_sim_func_nb=pre_sim_func_nb, pre_sim_args=(call_i, pre_sim_lst, sub_arg),
5430
post_sim_func_nb=post_sim_func_nb, post_sim_args=(call_i, post_sim_lst, sub_arg),
5431
pre_row_func_nb=pre_row_func_nb, pre_row_args=(pre_row_lst, sub_arg),
5432
post_row_func_nb=post_row_func_nb, post_row_args=(post_row_lst, sub_arg),
5433
pre_segment_func_nb=pre_segment_func_nb, pre_segment_args=(pre_segment_lst, sub_arg),
5434
post_segment_func_nb=post_segment_func_nb, post_segment_args=(post_segment_lst, sub_arg),
5435
post_order_func_nb=post_order_func_nb, post_order_args=(post_order_lst, sub_arg),
5436
segment_mask=segment_mask, call_pre_segment=True, call_post_segment=True,
5437
row_wise=True, flexible=True, template_mapping=dict(np=np)
5438
)
5439
assert call_i[0] == 48
5440
assert list(pre_sim_lst) == [1]
5441
assert list(post_sim_lst) == [48]
5442
assert list(pre_row_lst) == [2, 8, 17, 28, 42]
5443
assert list(post_row_lst) == [7, 16, 27, 41, 47]
5444
assert list(pre_segment_lst) == [3, 5, 9, 11, 18, 25, 29, 36, 43, 45]
5445
assert list(post_segment_lst) == [4, 6, 10, 15, 24, 26, 35, 40, 44, 46]
5446
assert list(order_lst) == [12, 14, 19, 21, 23, 30, 32, 34, 37, 39]
5447
assert list(post_order_lst) == [13, 20, 22, 31, 33, 38]
5448
5449
call_i = np.array([0])
5450
pre_sim_lst = List.empty_list(typeof(0))
5451
post_sim_lst = List.empty_list(typeof(0))
5452
pre_row_lst = List.empty_list(typeof(0))
5453
post_row_lst = List.empty_list(typeof(0))
5454
pre_segment_lst = List.empty_list(typeof(0))
5455
post_segment_lst = List.empty_list(typeof(0))
5456
order_lst = List.empty_list(typeof(0))
5457
post_order_lst = List.empty_list(typeof(0))
5458
_ = vbt.Portfolio.from_order_func(
5459
price_wide, flex_order_func_nb, order_lst, sub_arg,
5460
group_by=np.array([0, 0, 1]),
5461
pre_sim_func_nb=pre_sim_func_nb, pre_sim_args=(call_i, pre_sim_lst, sub_arg),
5462
post_sim_func_nb=post_sim_func_nb, post_sim_args=(call_i, post_sim_lst, sub_arg),
5463
pre_row_func_nb=pre_row_func_nb, pre_row_args=(pre_row_lst, sub_arg),
5464
post_row_func_nb=post_row_func_nb, post_row_args=(post_row_lst, sub_arg),
5465
pre_segment_func_nb=pre_segment_func_nb, pre_segment_args=(pre_segment_lst, sub_arg),
5466
post_segment_func_nb=post_segment_func_nb, post_segment_args=(post_segment_lst, sub_arg),
5467
post_order_func_nb=post_order_func_nb, post_order_args=(post_order_lst, sub_arg),
5468
segment_mask=segment_mask, call_pre_segment=False, call_post_segment=False,
5469
row_wise=True, flexible=True, template_mapping=dict(np=np)
5470
)
5471
assert call_i[0] == 36
5472
assert list(pre_sim_lst) == [1]
5473
assert list(post_sim_lst) == [36]
5474
assert list(pre_row_lst) == [2, 4, 11, 20, 34]
5475
assert list(post_row_lst) == [3, 10, 19, 33, 35]
5476
assert list(pre_segment_lst) == [5, 12, 21, 28]
5477
assert list(post_segment_lst) == [9, 18, 27, 32]
5478
assert list(order_lst) == [6, 8, 13, 15, 17, 22, 24, 26, 29, 31]
5479
assert list(post_order_lst) == [7, 14, 16, 23, 25, 30]
5480
5481
@pytest.mark.parametrize("test_row_wise", [False, True])
5482
@pytest.mark.parametrize("test_flexible", [False, True])
5483
def test_max_orders(self, test_row_wise, test_flexible):
5484
order_func = flex_order_func_nb if test_flexible else order_func_nb
5485
_ = vbt.Portfolio.from_order_func(
5486
price_wide, order_func, np.asarray(np.inf),
5487
row_wise=test_row_wise, flexible=test_flexible)
5488
_ = vbt.Portfolio.from_order_func(
5489
price_wide, order_func, np.asarray(np.inf),
5490
row_wise=test_row_wise, max_orders=15, flexible=test_flexible)
5491
with pytest.raises(Exception):
5492
_ = vbt.Portfolio.from_order_func(
5493
price_wide, order_func, np.asarray(np.inf),
5494
row_wise=test_row_wise, max_orders=14, flexible=test_flexible)
5495
5496
@pytest.mark.parametrize("test_row_wise", [False, True])
5497
@pytest.mark.parametrize("test_flexible", [False, True])
5498
def test_max_logs(self, test_row_wise, test_flexible):
5499
log_order_func = log_flex_order_func_nb if test_flexible else log_order_func_nb
5500
_ = vbt.Portfolio.from_order_func(
5501
price_wide, log_order_func, np.asarray(np.inf),
5502
row_wise=test_row_wise, flexible=test_flexible)
5503
_ = vbt.Portfolio.from_order_func(
5504
price_wide, log_order_func, np.asarray(np.inf),
5505
row_wise=test_row_wise, max_logs=15, flexible=test_flexible)
5506
with pytest.raises(Exception):
5507
_ = vbt.Portfolio.from_order_func(
5508
price_wide, log_order_func, np.asarray(np.inf),
5509
row_wise=test_row_wise, max_logs=14, flexible=test_flexible)
5510
5511
5512
# ############# Portfolio ############# #
5513
5514
price_na = pd.DataFrame({
5515
'a': [np.nan, 2., 3., 4., 5.],
5516
'b': [1., 2., np.nan, 4., 5.],
5517
'c': [1., 2., 3., 4., np.nan]
5518
}, index=price.index)
5519
order_size_new = pd.Series([1., 0.1, -1., -0.1, 1.])
5520
directions = ['longonly', 'shortonly', 'both']
5521
group_by = pd.Index(['first', 'first', 'second'], name='group')
5522
5523
pf = vbt.Portfolio.from_orders(
5524
price_na, order_size_new, size_type='amount', direction=directions,
5525
fees=0.01, fixed_fees=0.1, slippage=0.01, log=True,
5526
call_seq='reversed', group_by=None,
5527
init_cash=[100., 100., 100.], freq='1D', attach_call_seq=True
5528
) # independent
5529
5530
pf_grouped = vbt.Portfolio.from_orders(
5531
price_na, order_size_new, size_type='amount', direction=directions,
5532
fees=0.01, fixed_fees=0.1, slippage=0.01, log=True,
5533
call_seq='reversed', group_by=group_by, cash_sharing=False,
5534
init_cash=[100., 100., 100.], freq='1D', attach_call_seq=True
5535
) # grouped
5536
5537
pf_shared = vbt.Portfolio.from_orders(
5538
price_na, order_size_new, size_type='amount', direction=directions,
5539
fees=0.01, fixed_fees=0.1, slippage=0.01, log=True,
5540
call_seq='reversed', group_by=group_by, cash_sharing=True,
5541
init_cash=[200., 100.], freq='1D', attach_call_seq=True
5542
) # shared
5543
5544
5545
class TestPortfolio:
5546
def test_config(self, tmp_path):
5547
pf2 = pf.copy()
5548
pf2._metrics = pf2._metrics.copy()
5549
pf2.metrics['hello'] = 'world'
5550
pf2._subplots = pf2.subplots.copy()
5551
pf2.subplots['hello'] = 'world'
5552
assert vbt.Portfolio.loads(pf2['a'].dumps()) == pf2['a']
5553
assert vbt.Portfolio.loads(pf2.dumps()) == pf2
5554
pf2.save(tmp_path / 'pf')
5555
assert vbt.Portfolio.load(tmp_path / 'pf') == pf2
5556
5557
def test_wrapper(self):
5558
pd.testing.assert_index_equal(
5559
pf.wrapper.index,
5560
price_na.index
5561
)
5562
pd.testing.assert_index_equal(
5563
pf.wrapper.columns,
5564
price_na.columns
5565
)
5566
assert pf.wrapper.ndim == 2
5567
assert pf.wrapper.grouper.group_by is None
5568
assert pf.wrapper.grouper.allow_enable
5569
assert pf.wrapper.grouper.allow_disable
5570
assert pf.wrapper.grouper.allow_modify
5571
pd.testing.assert_index_equal(
5572
pf_grouped.wrapper.index,
5573
price_na.index
5574
)
5575
pd.testing.assert_index_equal(
5576
pf_grouped.wrapper.columns,
5577
price_na.columns
5578
)
5579
assert pf_grouped.wrapper.ndim == 2
5580
pd.testing.assert_index_equal(
5581
pf_grouped.wrapper.grouper.group_by,
5582
group_by
5583
)
5584
assert pf_grouped.wrapper.grouper.allow_enable
5585
assert pf_grouped.wrapper.grouper.allow_disable
5586
assert pf_grouped.wrapper.grouper.allow_modify
5587
pd.testing.assert_index_equal(
5588
pf_shared.wrapper.index,
5589
price_na.index
5590
)
5591
pd.testing.assert_index_equal(
5592
pf_shared.wrapper.columns,
5593
price_na.columns
5594
)
5595
assert pf_shared.wrapper.ndim == 2
5596
pd.testing.assert_index_equal(
5597
pf_shared.wrapper.grouper.group_by,
5598
group_by
5599
)
5600
assert not pf_shared.wrapper.grouper.allow_enable
5601
assert pf_shared.wrapper.grouper.allow_disable
5602
assert not pf_shared.wrapper.grouper.allow_modify
5603
5604
def test_indexing(self):
5605
assert pf['a'].wrapper == pf.wrapper['a']
5606
assert pf['a'].orders == pf.orders['a']
5607
assert pf['a'].logs == pf.logs['a']
5608
assert pf['a'].init_cash == pf.init_cash['a']
5609
pd.testing.assert_series_equal(pf['a'].call_seq, pf.call_seq['a'])
5610
5611
assert pf['c'].wrapper == pf.wrapper['c']
5612
assert pf['c'].orders == pf.orders['c']
5613
assert pf['c'].logs == pf.logs['c']
5614
assert pf['c'].init_cash == pf.init_cash['c']
5615
pd.testing.assert_series_equal(pf['c'].call_seq, pf.call_seq['c'])
5616
5617
assert pf[['c']].wrapper == pf.wrapper[['c']]
5618
assert pf[['c']].orders == pf.orders[['c']]
5619
assert pf[['c']].logs == pf.logs[['c']]
5620
pd.testing.assert_series_equal(pf[['c']].init_cash, pf.init_cash[['c']])
5621
pd.testing.assert_frame_equal(pf[['c']].call_seq, pf.call_seq[['c']])
5622
5623
assert pf_grouped['first'].wrapper == pf_grouped.wrapper['first']
5624
assert pf_grouped['first'].orders == pf_grouped.orders['first']
5625
assert pf_grouped['first'].logs == pf_grouped.logs['first']
5626
assert pf_grouped['first'].init_cash == pf_grouped.init_cash['first']
5627
pd.testing.assert_frame_equal(pf_grouped['first'].call_seq, pf_grouped.call_seq[['a', 'b']])
5628
5629
assert pf_grouped[['first']].wrapper == pf_grouped.wrapper[['first']]
5630
assert pf_grouped[['first']].orders == pf_grouped.orders[['first']]
5631
assert pf_grouped[['first']].logs == pf_grouped.logs[['first']]
5632
pd.testing.assert_series_equal(
5633
pf_grouped[['first']].init_cash,
5634
pf_grouped.init_cash[['first']])
5635
pd.testing.assert_frame_equal(pf_grouped[['first']].call_seq, pf_grouped.call_seq[['a', 'b']])
5636
5637
assert pf_grouped['second'].wrapper == pf_grouped.wrapper['second']
5638
assert pf_grouped['second'].orders == pf_grouped.orders['second']
5639
assert pf_grouped['second'].logs == pf_grouped.logs['second']
5640
assert pf_grouped['second'].init_cash == pf_grouped.init_cash['second']
5641
pd.testing.assert_series_equal(pf_grouped['second'].call_seq, pf_grouped.call_seq['c'])
5642
5643
assert pf_grouped[['second']].orders == pf_grouped.orders[['second']]
5644
assert pf_grouped[['second']].wrapper == pf_grouped.wrapper[['second']]
5645
assert pf_grouped[['second']].orders == pf_grouped.orders[['second']]
5646
assert pf_grouped[['second']].logs == pf_grouped.logs[['second']]
5647
pd.testing.assert_series_equal(
5648
pf_grouped[['second']].init_cash,
5649
pf_grouped.init_cash[['second']])
5650
pd.testing.assert_frame_equal(pf_grouped[['second']].call_seq, pf_grouped.call_seq[['c']])
5651
5652
assert pf_shared['first'].wrapper == pf_shared.wrapper['first']
5653
assert pf_shared['first'].orders == pf_shared.orders['first']
5654
assert pf_shared['first'].logs == pf_shared.logs['first']
5655
assert pf_shared['first'].init_cash == pf_shared.init_cash['first']
5656
pd.testing.assert_frame_equal(pf_shared['first'].call_seq, pf_shared.call_seq[['a', 'b']])
5657
5658
assert pf_shared[['first']].orders == pf_shared.orders[['first']]
5659
assert pf_shared[['first']].wrapper == pf_shared.wrapper[['first']]
5660
assert pf_shared[['first']].orders == pf_shared.orders[['first']]
5661
assert pf_shared[['first']].logs == pf_shared.logs[['first']]
5662
pd.testing.assert_series_equal(
5663
pf_shared[['first']].init_cash,
5664
pf_shared.init_cash[['first']])
5665
pd.testing.assert_frame_equal(pf_shared[['first']].call_seq, pf_shared.call_seq[['a', 'b']])
5666
5667
assert pf_shared['second'].wrapper == pf_shared.wrapper['second']
5668
assert pf_shared['second'].orders == pf_shared.orders['second']
5669
assert pf_shared['second'].logs == pf_shared.logs['second']
5670
assert pf_shared['second'].init_cash == pf_shared.init_cash['second']
5671
pd.testing.assert_series_equal(pf_shared['second'].call_seq, pf_shared.call_seq['c'])
5672
5673
assert pf_shared[['second']].wrapper == pf_shared.wrapper[['second']]
5674
assert pf_shared[['second']].orders == pf_shared.orders[['second']]
5675
assert pf_shared[['second']].logs == pf_shared.logs[['second']]
5676
pd.testing.assert_series_equal(
5677
pf_shared[['second']].init_cash,
5678
pf_shared.init_cash[['second']])
5679
pd.testing.assert_frame_equal(pf_shared[['second']].call_seq, pf_shared.call_seq[['c']])
5680
5681
def test_regroup(self):
5682
assert pf.regroup(None) == pf
5683
assert pf.regroup(False) == pf
5684
assert pf.regroup(group_by) != pf
5685
pd.testing.assert_index_equal(pf.regroup(group_by).wrapper.grouper.group_by, group_by)
5686
assert pf_grouped.regroup(None) == pf_grouped
5687
assert pf_grouped.regroup(False) != pf_grouped
5688
assert pf_grouped.regroup(False).wrapper.grouper.group_by is None
5689
assert pf_grouped.regroup(group_by) == pf_grouped
5690
assert pf_shared.regroup(None) == pf_shared
5691
with pytest.raises(Exception):
5692
_ = pf_shared.regroup(False)
5693
assert pf_shared.regroup(group_by) == pf_shared
5694
5695
def test_cash_sharing(self):
5696
assert not pf.cash_sharing
5697
assert not pf_grouped.cash_sharing
5698
assert pf_shared.cash_sharing
5699
5700
def test_call_seq(self):
5701
pd.testing.assert_frame_equal(
5702
pf.call_seq,
5703
pd.DataFrame(
5704
np.array([
5705
[0, 0, 0],
5706
[0, 0, 0],
5707
[0, 0, 0],
5708
[0, 0, 0],
5709
[0, 0, 0]
5710
]),
5711
index=price_na.index,
5712
columns=price_na.columns
5713
)
5714
)
5715
pd.testing.assert_frame_equal(
5716
pf_grouped.call_seq,
5717
pd.DataFrame(
5718
np.array([
5719
[1, 0, 0],
5720
[1, 0, 0],
5721
[1, 0, 0],
5722
[1, 0, 0],
5723
[1, 0, 0]
5724
]),
5725
index=price_na.index,
5726
columns=price_na.columns
5727
)
5728
)
5729
pd.testing.assert_frame_equal(
5730
pf_shared.call_seq,
5731
pd.DataFrame(
5732
np.array([
5733
[1, 0, 0],
5734
[1, 0, 0],
5735
[1, 0, 0],
5736
[1, 0, 0],
5737
[1, 0, 0]
5738
]),
5739
index=price_na.index,
5740
columns=price_na.columns
5741
)
5742
)
5743
5744
def test_orders(self):
5745
record_arrays_close(
5746
pf.orders.values,
5747
np.array([
5748
(0, 0, 1, 0.1, 2.02, 0.10202, 0), (1, 0, 2, 0.1, 2.9699999999999998, 0.10297, 1),
5749
(2, 0, 4, 1.0, 5.05, 0.1505, 0), (3, 1, 0, 1.0, 0.99, 0.10990000000000001, 1),
5750
(4, 1, 1, 0.1, 1.98, 0.10198, 1), (5, 1, 3, 0.1, 4.04, 0.10404000000000001, 0),
5751
(6, 1, 4, 1.0, 4.95, 0.14950000000000002, 1), (7, 2, 0, 1.0, 1.01, 0.1101, 0),
5752
(8, 2, 1, 0.1, 2.02, 0.10202, 0), (9, 2, 2, 1.0, 2.9699999999999998, 0.1297, 1),
5753
(10, 2, 3, 0.1, 3.96, 0.10396000000000001, 1)
5754
], dtype=order_dt)
5755
)
5756
result = pd.Series(
5757
np.array([3, 4, 4]),
5758
index=price_na.columns
5759
).rename('count')
5760
pd.testing.assert_series_equal(
5761
pf.orders.count(),
5762
result
5763
)
5764
pd.testing.assert_series_equal(
5765
pf_grouped.get_orders(group_by=False).count(),
5766
result
5767
)
5768
pd.testing.assert_series_equal(
5769
pf_shared.get_orders(group_by=False).count(),
5770
result
5771
)
5772
result = pd.Series(
5773
np.array([7, 4]),
5774
index=pd.Index(['first', 'second'], dtype='object', name='group')
5775
).rename('count')
5776
pd.testing.assert_series_equal(
5777
pf.get_orders(group_by=group_by).count(),
5778
result
5779
)
5780
pd.testing.assert_series_equal(
5781
pf_grouped.orders.count(),
5782
result
5783
)
5784
pd.testing.assert_series_equal(
5785
pf_shared.orders.count(),
5786
result
5787
)
5788
5789
def test_logs(self):
5790
record_arrays_close(
5791
pf.logs.values,
5792
np.array([
5793
(0, 0, 0, 0, 100.0, 0.0, 0.0, 100.0, np.nan, 100.0, 1.0, np.nan, 0, 0, 0.01, 0.1,
5794
0.01, 1e-08, np.inf, np.nan, 0.0, False, True, False, True, 100.0, 0.0, 0.0, 100.0,
5795
np.nan, 100.0, np.nan, np.nan, np.nan, -1, 1, 1, -1),
5796
(1, 0, 0, 1, 100.0, 0.0, 0.0, 100.0, 2.0, 100.0, 0.1, 2.0, 0, 0, 0.01, 0.1,
5797
0.01, 1e-08, np.inf, np.nan, 0.0, False, True, False, True, 99.69598, 0.1, 0.0,
5798
99.69598, 2.0, 100.0, 0.1, 2.02, 0.10202, 0, 0, -1, 0),
5799
(2, 0, 0, 2, 99.69598, 0.1, 0.0, 99.69598, 3.0, 99.99598, -1.0, 3.0, 0,
5800
0, 0.01, 0.1, 0.01, 1e-08, np.inf, np.nan, 0.0, False, True, False, True,
5801
99.89001, 0.0, 0.0, 99.89001, 3.0, 99.99598, 0.1, 2.9699999999999998, 0.10297, 1, 0, -1, 1),
5802
(3, 0, 0, 3, 99.89001, 0.0, 0.0, 99.89001, 4.0, 99.89001, -0.1, 4.0, 0, 0,
5803
0.01, 0.1, 0.01, 1e-08, np.inf, np.nan, 0.0, False, True, False, True, 99.89001,
5804
0.0, 0.0, 99.89001, 4.0, 99.89001, np.nan, np.nan, np.nan, -1, 2, 8, -1),
5805
(4, 0, 0, 4, 99.89001, 0.0, 0.0, 99.89001, 5.0, 99.89001, 1.0, 5.0, 0, 0,
5806
0.01, 0.1, 0.01, 1e-08, np.inf, np.nan, 0.0, False, True, False, True, 94.68951,
5807
1.0, 0.0, 94.68951, 5.0, 99.89001, 1.0, 5.05, 0.1505, 0, 0, -1, 2),
5808
(5, 1, 1, 0, 100.0, 0.0, 0.0, 100.0, 1.0, 100.0, 1.0, 1.0, 0, 1, 0.01, 0.1, 0.01,
5809
1e-08, np.inf, np.nan, 0.0, False, True, False, True, 100.8801, -1.0, 0.99, 98.9001,
5810
1.0, 100.0, 1.0, 0.99, 0.10990000000000001, 1, 0, -1, 3),
5811
(6, 1, 1, 1, 100.8801, -1.0, 0.99, 98.9001, 2.0, 98.8801, 0.1, 2.0, 0, 1, 0.01,
5812
0.1, 0.01, 1e-08, np.inf, np.nan, 0.0, False, True, False, True, 100.97612, -1.1,
5813
1.188, 98.60011999999999, 2.0, 98.8801, 0.1, 1.98, 0.10198, 1, 0, -1, 4),
5814
(7, 1, 1, 2, 100.97612, -1.1, 1.188, 98.60011999999999, 2.0, 98.77611999999999,
5815
-1.0, np.nan, 0, 1, 0.01, 0.1, 0.01, 1e-08, np.inf, np.nan, 0.0, False, True, False, True, 100.97612,
5816
-1.1, 1.188, 98.60011999999999, 2.0, 98.77611999999999, np.nan, np.nan, np.nan, -1, 1, 1, -1),
5817
(8, 1, 1, 3, 100.97612, -1.1, 1.188, 98.60011999999999, 4.0, 96.57611999999999, -0.1, 4.0,
5818
0, 1, 0.01, 0.1, 0.01, 1e-08, np.inf, np.nan, 0.0, False, True, False, True, 100.46808, -1.0,
5819
1.08, 98.30807999999999, 4.0, 96.57611999999999, 0.1, 4.04, 0.10404000000000001, 0, 0, -1, 5),
5820
(9, 1, 1, 4, 100.46808, -1.0, 1.08, 98.30807999999999, 5.0, 95.46808, 1.0, 5.0, 0, 1,
5821
0.01, 0.1, 0.01, 1e-08, np.inf, np.nan, 0.0, False, True, False, True, 105.26858, -2.0, 6.03,
5822
93.20857999999998, 5.0, 95.46808, 1.0, 4.95, 0.14950000000000002, 1, 0, -1, 6),
5823
(10, 2, 2, 0, 100.0, 0.0, 0.0, 100.0, 1.0, 100.0, 1.0, 1.0, 0, 2, 0.01, 0.1, 0.01, 1e-08,
5824
np.inf, np.nan, 0.0, False, True, False, True, 98.8799, 1.0, 0.0, 98.8799, 1.0, 100.0, 1.0,
5825
1.01, 0.1101, 0, 0, -1, 7),
5826
(11, 2, 2, 1, 98.8799, 1.0, 0.0, 98.8799, 2.0, 100.8799, 0.1, 2.0, 0, 2, 0.01,
5827
0.1, 0.01, 1e-08, np.inf, np.nan, 0.0, False, True, False, True, 98.57588000000001,
5828
1.1, 0.0, 98.57588000000001, 2.0, 100.8799, 0.1, 2.02, 0.10202, 0, 0, -1, 8),
5829
(12, 2, 2, 2, 98.57588000000001, 1.1, 0.0, 98.57588000000001, 3.0, 101.87588000000001,
5830
-1.0, 3.0, 0, 2, 0.01, 0.1, 0.01, 1e-08, np.inf, np.nan, 0.0, False, True, False, True,
5831
101.41618000000001, 0.10000000000000009, 0.0, 101.41618000000001, 3.0, 101.87588000000001,
5832
1.0, 2.9699999999999998, 0.1297, 1, 0, -1, 9),
5833
(13, 2, 2, 3, 101.41618000000001, 0.10000000000000009, 0.0, 101.41618000000001, 4.0,
5834
101.81618000000002, -0.1, 4.0, 0, 2, 0.01, 0.1, 0.01, 1e-08, np.inf, np.nan, 0.0, False,
5835
True, False, True, 101.70822000000001, 0.0, 0.0, 101.70822000000001, 4.0,
5836
101.81618000000002, 0.1, 3.96, 0.10396000000000001, 1, 0, -1, 10),
5837
(14, 2, 2, 4, 101.70822000000001, 0.0, 0.0, 101.70822000000001, 4.0, 101.70822000000001,
5838
1.0, np.nan, 0, 2, 0.01, 0.1, 0.01, 1e-08, np.inf, np.nan, 0.0, False, True, False, True,
5839
101.70822000000001, 0.0, 0.0, 101.70822000000001, 4.0, 101.70822000000001, np.nan,
5840
np.nan, np.nan, -1, 1, 1, -1)
5841
], dtype=log_dt)
5842
)
5843
result = pd.Series(
5844
np.array([5, 5, 5]),
5845
index=price_na.columns
5846
).rename('count')
5847
pd.testing.assert_series_equal(
5848
pf.logs.count(),
5849
result
5850
)
5851
pd.testing.assert_series_equal(
5852
pf_grouped.get_logs(group_by=False).count(),
5853
result
5854
)
5855
pd.testing.assert_series_equal(
5856
pf_shared.get_logs(group_by=False).count(),
5857
result
5858
)
5859
result = pd.Series(
5860
np.array([10, 5]),
5861
index=pd.Index(['first', 'second'], dtype='object', name='group')
5862
).rename('count')
5863
pd.testing.assert_series_equal(
5864
pf.get_logs(group_by=group_by).count(),
5865
result
5866
)
5867
pd.testing.assert_series_equal(
5868
pf_grouped.logs.count(),
5869
result
5870
)
5871
pd.testing.assert_series_equal(
5872
pf_shared.logs.count(),
5873
result
5874
)
5875
5876
def test_entry_trades(self):
5877
record_arrays_close(
5878
pf.entry_trades.values,
5879
np.array([
5880
(0, 0, 0.1, 1, 2.02, 0.10202, 2, 2.9699999999999998, 0.10297,
5881
-0.10999000000000003, -0.5445049504950497, 0, 1, 0),
5882
(1, 0, 1.0, 4, 5.05, 0.1505, 4, 5.0, 0.0, -0.20049999999999982, -0.03970297029702967, 0, 0, 1),
5883
(2, 1, 1.0, 0, 0.99, 0.10990000000000001, 4, 4.954285714285714,
5884
0.049542857142857145, -4.12372857142857, -4.165382395382394, 1, 0, 2),
5885
(3, 1, 0.1, 1, 1.98, 0.10198, 4, 4.954285714285714, 0.004954285714285714,
5886
-0.4043628571428571, -2.0422366522366517, 1, 0, 2),
5887
(4, 1, 1.0, 4, 4.95, 0.14950000000000002, 4, 4.954285714285714,
5888
0.049542857142857145, -0.20332857142857072, -0.04107647907647893, 1, 0, 2),
5889
(5, 2, 1.0, 0, 1.01, 0.1101, 3, 3.0599999999999996, 0.21241818181818184,
5890
1.727481818181818, 1.71037803780378, 0, 1, 3),
5891
(6, 2, 0.1, 1, 2.02, 0.10202, 3, 3.0599999999999996, 0.021241818181818185,
5892
-0.019261818181818203, -0.09535553555355546, 0, 1, 3)
5893
], dtype=trade_dt)
5894
)
5895
result = pd.Series(
5896
np.array([2, 3, 2]),
5897
index=price_na.columns
5898
).rename('count')
5899
pd.testing.assert_series_equal(
5900
pf.entry_trades.count(),
5901
result
5902
)
5903
pd.testing.assert_series_equal(
5904
pf_grouped.get_entry_trades(group_by=False).count(),
5905
result
5906
)
5907
pd.testing.assert_series_equal(
5908
pf_shared.get_entry_trades(group_by=False).count(),
5909
result
5910
)
5911
result = pd.Series(
5912
np.array([5, 2]),
5913
index=pd.Index(['first', 'second'], dtype='object', name='group')
5914
).rename('count')
5915
pd.testing.assert_series_equal(
5916
pf.get_entry_trades(group_by=group_by).count(),
5917
result
5918
)
5919
pd.testing.assert_series_equal(
5920
pf_grouped.entry_trades.count(),
5921
result
5922
)
5923
pd.testing.assert_series_equal(
5924
pf_shared.entry_trades.count(),
5925
result
5926
)
5927
5928
def test_exit_trades(self):
5929
record_arrays_close(
5930
pf.exit_trades.values,
5931
np.array([
5932
(0, 0, 0.1, 1, 2.02, 0.10202, 2, 2.9699999999999998, 0.10297,
5933
-0.10999000000000003, -0.5445049504950497, 0, 1, 0),
5934
(1, 0, 1.0, 4, 5.05, 0.1505, 4, 5.0, 0.0,
5935
-0.20049999999999982, -0.03970297029702967, 0, 0, 1),
5936
(2, 1, 0.1, 0, 1.0799999999999998, 0.019261818181818182,
5937
3, 4.04, 0.10404000000000001, -0.4193018181818182, -3.882424242424243, 1, 1, 2),
5938
(3, 1, 2.0, 0, 3.015, 0.3421181818181819, 4, 5.0, 0.0,
5939
-4.312118181818182, -0.7151108095884214, 1, 0, 2),
5940
(4, 2, 1.0, 0, 1.1018181818181818, 0.19283636363636364, 2,
5941
2.9699999999999998, 0.1297, 1.5456454545454543, 1.4028135313531351, 0, 1, 3),
5942
(5, 2, 0.10000000000000009, 0, 1.1018181818181818, 0.019283636363636378,
5943
3, 3.96, 0.10396000000000001, 0.1625745454545457, 1.4755115511551162, 0, 1, 3)
5944
], dtype=trade_dt)
5945
)
5946
result = pd.Series(
5947
np.array([2, 2, 2]),
5948
index=price_na.columns
5949
).rename('count')
5950
pd.testing.assert_series_equal(
5951
pf.exit_trades.count(),
5952
result
5953
)
5954
pd.testing.assert_series_equal(
5955
pf_grouped.get_exit_trades(group_by=False).count(),
5956
result
5957
)
5958
pd.testing.assert_series_equal(
5959
pf_shared.get_exit_trades(group_by=False).count(),
5960
result
5961
)
5962
result = pd.Series(
5963
np.array([4, 2]),
5964
index=pd.Index(['first', 'second'], dtype='object', name='group')
5965
).rename('count')
5966
pd.testing.assert_series_equal(
5967
pf.get_exit_trades(group_by=group_by).count(),
5968
result
5969
)
5970
pd.testing.assert_series_equal(
5971
pf_grouped.exit_trades.count(),
5972
result
5973
)
5974
pd.testing.assert_series_equal(
5975
pf_shared.exit_trades.count(),
5976
result
5977
)
5978
5979
def test_positions(self):
5980
record_arrays_close(
5981
pf.positions.values,
5982
np.array([
5983
(0, 0, 0.1, 1, 2.02, 0.10202, 2, 2.9699999999999998,
5984
0.10297, -0.10999000000000003, -0.5445049504950497, 0, 1, 0),
5985
(1, 0, 1.0, 4, 5.05, 0.1505, 4, 5.0, 0.0,
5986
-0.20049999999999982, -0.03970297029702967, 0, 0, 1),
5987
(2, 1, 2.1, 0, 2.9228571428571426, 0.36138000000000003, 4, 4.954285714285714,
5988
0.10404000000000001, -4.731420000000001, -0.7708406647116326, 1, 0, 2),
5989
(3, 2, 1.1, 0, 1.1018181818181818, 0.21212000000000003, 3,
5990
3.06, 0.23366000000000003, 1.7082200000000003, 1.4094224422442245, 0, 1, 3)
5991
], dtype=trade_dt)
5992
)
5993
result = pd.Series(
5994
np.array([2, 1, 1]),
5995
index=price_na.columns
5996
).rename('count')
5997
pd.testing.assert_series_equal(
5998
pf.positions.count(),
5999
result
6000
)
6001
pd.testing.assert_series_equal(
6002
pf_grouped.get_positions(group_by=False).count(),
6003
result
6004
)
6005
pd.testing.assert_series_equal(
6006
pf_shared.get_positions(group_by=False).count(),
6007
result
6008
)
6009
result = pd.Series(
6010
np.array([3, 1]),
6011
index=pd.Index(['first', 'second'], dtype='object', name='group')
6012
).rename('count')
6013
pd.testing.assert_series_equal(
6014
pf.get_positions(group_by=group_by).count(),
6015
result
6016
)
6017
pd.testing.assert_series_equal(
6018
pf_grouped.positions.count(),
6019
result
6020
)
6021
pd.testing.assert_series_equal(
6022
pf_shared.positions.count(),
6023
result
6024
)
6025
6026
def test_drawdowns(self):
6027
record_arrays_close(
6028
pf.drawdowns.values,
6029
np.array([
6030
(0, 0, 0, 1, 4, 4, 100.0, 99.68951, 99.68951, 0),
6031
(1, 1, 0, 1, 4, 4, 99.8801, 95.26858, 95.26858, 0),
6032
(2, 2, 2, 3, 3, 4, 101.71618000000001, 101.70822000000001, 101.70822000000001, 0)
6033
], dtype=drawdown_dt)
6034
)
6035
result = pd.Series(
6036
np.array([1, 1, 1]),
6037
index=price_na.columns
6038
).rename('count')
6039
pd.testing.assert_series_equal(
6040
pf.drawdowns.count(),
6041
result
6042
)
6043
pd.testing.assert_series_equal(
6044
pf_grouped.get_drawdowns(group_by=False).count(),
6045
result
6046
)
6047
pd.testing.assert_series_equal(
6048
pf_shared.get_drawdowns(group_by=False).count(),
6049
result
6050
)
6051
result = pd.Series(
6052
np.array([1, 1]),
6053
index=pd.Index(['first', 'second'], dtype='object', name='group')
6054
).rename('count')
6055
pd.testing.assert_series_equal(
6056
pf.get_drawdowns(group_by=group_by).count(),
6057
result
6058
)
6059
pd.testing.assert_series_equal(
6060
pf_grouped.drawdowns.count(),
6061
result
6062
)
6063
pd.testing.assert_series_equal(
6064
pf_shared.drawdowns.count(),
6065
result
6066
)
6067
6068
def test_close(self):
6069
pd.testing.assert_frame_equal(pf.close, price_na)
6070
pd.testing.assert_frame_equal(pf_grouped.close, price_na)
6071
pd.testing.assert_frame_equal(pf_shared.close, price_na)
6072
6073
def test_get_filled_close(self):
6074
pd.testing.assert_frame_equal(
6075
pf.get_filled_close(),
6076
price_na.ffill().bfill()
6077
)
6078
6079
def test_asset_flow(self):
6080
pd.testing.assert_frame_equal(
6081
pf.asset_flow(direction='longonly'),
6082
pd.DataFrame(
6083
np.array([
6084
[0., 0., 1.],
6085
[0.1, 0., 0.1],
6086
[-0.1, 0., -1.],
6087
[0., 0., -0.1],
6088
[1., 0., 0.]
6089
]),
6090
index=price_na.index,
6091
columns=price_na.columns
6092
)
6093
)
6094
pd.testing.assert_frame_equal(
6095
pf.asset_flow(direction='shortonly'),
6096
pd.DataFrame(
6097
np.array([
6098
[0., 1., 0.],
6099
[0., 0.1, 0.],
6100
[0., 0., 0.],
6101
[0., -0.1, 0.],
6102
[0., 1., 0.]
6103
]),
6104
index=price_na.index,
6105
columns=price_na.columns
6106
)
6107
)
6108
result = pd.DataFrame(
6109
np.array([
6110
[0., -1., 1.],
6111
[0.1, -0.1, 0.1],
6112
[-0.1, 0., -1.],
6113
[0., 0.1, -0.1],
6114
[1., -1., 0.]
6115
]),
6116
index=price_na.index,
6117
columns=price_na.columns
6118
)
6119
pd.testing.assert_frame_equal(
6120
pf.asset_flow(),
6121
result
6122
)
6123
pd.testing.assert_frame_equal(
6124
pf_grouped.asset_flow(),
6125
result
6126
)
6127
pd.testing.assert_frame_equal(
6128
pf_shared.asset_flow(),
6129
result
6130
)
6131
6132
def test_assets(self):
6133
pd.testing.assert_frame_equal(
6134
pf.assets(direction='longonly'),
6135
pd.DataFrame(
6136
np.array([
6137
[0., 0., 1.],
6138
[0.1, 0., 1.1],
6139
[0., 0., 0.1],
6140
[0., 0., 0.],
6141
[1., 0., 0.]
6142
]),
6143
index=price_na.index,
6144
columns=price_na.columns
6145
)
6146
)
6147
pd.testing.assert_frame_equal(
6148
pf.assets(direction='shortonly'),
6149
pd.DataFrame(
6150
np.array([
6151
[0., 1., 0.],
6152
[0., 1.1, 0.],
6153
[0., 1.1, 0.],
6154
[0., 1., 0.],
6155
[0., 2., 0.]
6156
]),
6157
index=price_na.index,
6158
columns=price_na.columns
6159
)
6160
)
6161
result = pd.DataFrame(
6162
np.array([
6163
[0., -1., 1.],
6164
[0.1, -1.1, 1.1],
6165
[0., -1.1, 0.1],
6166
[0., -1., 0.],
6167
[1., -2., 0.]
6168
]),
6169
index=price_na.index,
6170
columns=price_na.columns
6171
)
6172
pd.testing.assert_frame_equal(
6173
pf.assets(),
6174
result
6175
)
6176
pd.testing.assert_frame_equal(
6177
pf_grouped.assets(),
6178
result
6179
)
6180
pd.testing.assert_frame_equal(
6181
pf_shared.assets(),
6182
result
6183
)
6184
6185
def test_position_mask(self):
6186
pd.testing.assert_frame_equal(
6187
pf.position_mask(direction='longonly'),
6188
pd.DataFrame(
6189
np.array([
6190
[False, False, True],
6191
[True, False, True],
6192
[False, False, True],
6193
[False, False, False],
6194
[True, False, False]
6195
]),
6196
index=price_na.index,
6197
columns=price_na.columns
6198
)
6199
)
6200
pd.testing.assert_frame_equal(
6201
pf.position_mask(direction='shortonly'),
6202
pd.DataFrame(
6203
np.array([
6204
[False, True, False],
6205
[False, True, False],
6206
[False, True, False],
6207
[False, True, False],
6208
[False, True, False]
6209
]),
6210
index=price_na.index,
6211
columns=price_na.columns
6212
)
6213
)
6214
result = pd.DataFrame(
6215
np.array([
6216
[False, True, True],
6217
[True, True, True],
6218
[False, True, True],
6219
[False, True, False],
6220
[True, True, False]
6221
]),
6222
index=price_na.index,
6223
columns=price_na.columns
6224
)
6225
pd.testing.assert_frame_equal(
6226
pf.position_mask(),
6227
result
6228
)
6229
pd.testing.assert_frame_equal(
6230
pf_grouped.position_mask(group_by=False),
6231
result
6232
)
6233
pd.testing.assert_frame_equal(
6234
pf_shared.position_mask(group_by=False),
6235
result
6236
)
6237
result = pd.DataFrame(
6238
np.array([
6239
[True, True],
6240
[True, True],
6241
[True, True],
6242
[True, False],
6243
[True, False]
6244
]),
6245
index=price_na.index,
6246
columns=pd.Index(['first', 'second'], dtype='object', name='group')
6247
)
6248
pd.testing.assert_frame_equal(
6249
pf.position_mask(group_by=group_by),
6250
result
6251
)
6252
pd.testing.assert_frame_equal(
6253
pf_grouped.position_mask(),
6254
result
6255
)
6256
pd.testing.assert_frame_equal(
6257
pf_shared.position_mask(),
6258
result
6259
)
6260
6261
def test_position_coverage(self):
6262
pd.testing.assert_series_equal(
6263
pf.position_coverage(direction='longonly'),
6264
pd.Series(np.array([0.4, 0., 0.6]), index=price_na.columns).rename('position_coverage')
6265
)
6266
pd.testing.assert_series_equal(
6267
pf.position_coverage(direction='shortonly'),
6268
pd.Series(np.array([0., 1., 0.]), index=price_na.columns).rename('position_coverage')
6269
)
6270
result = pd.Series(np.array([0.4, 1., 0.6]), index=price_na.columns).rename('position_coverage')
6271
pd.testing.assert_series_equal(
6272
pf.position_coverage(),
6273
result
6274
)
6275
pd.testing.assert_series_equal(
6276
pf_grouped.position_coverage(group_by=False),
6277
result
6278
)
6279
pd.testing.assert_series_equal(
6280
pf_shared.position_coverage(group_by=False),
6281
result
6282
)
6283
result = pd.Series(
6284
np.array([0.7, 0.6]),
6285
pd.Index(['first', 'second'], dtype='object', name='group')
6286
).rename('position_coverage')
6287
pd.testing.assert_series_equal(
6288
pf.position_coverage(group_by=group_by),
6289
result
6290
)
6291
pd.testing.assert_series_equal(
6292
pf_grouped.position_coverage(),
6293
result
6294
)
6295
pd.testing.assert_series_equal(
6296
pf_shared.position_coverage(),
6297
result
6298
)
6299
6300
def test_cash_flow(self):
6301
pd.testing.assert_frame_equal(
6302
pf.cash_flow(free=True),
6303
pd.DataFrame(
6304
np.array([
6305
[0.0, -1.0998999999999999, -1.1201],
6306
[-0.30402, -0.2999800000000002, -0.3040200000000002],
6307
[0.19402999999999998, 0.0, 2.8402999999999996],
6308
[0.0, -0.2920400000000002, 0.29204000000000035],
6309
[-5.2005, -5.0995, 0.0]
6310
]),
6311
index=price_na.index,
6312
columns=price_na.columns
6313
)
6314
)
6315
result = pd.DataFrame(
6316
np.array([
6317
[0., 0.8801, -1.1201],
6318
[-0.30402, 0.09602, -0.30402],
6319
[0.19403, 0., 2.8403],
6320
[0., -0.50804, 0.29204],
6321
[-5.2005, 4.8005, 0.]
6322
]),
6323
index=price_na.index,
6324
columns=price_na.columns
6325
)
6326
pd.testing.assert_frame_equal(
6327
pf.cash_flow(),
6328
result
6329
)
6330
pd.testing.assert_frame_equal(
6331
pf_grouped.cash_flow(group_by=False),
6332
result
6333
)
6334
pd.testing.assert_frame_equal(
6335
pf_shared.cash_flow(group_by=False),
6336
result
6337
)
6338
result = pd.DataFrame(
6339
np.array([
6340
[0.8801, -1.1201],
6341
[-0.208, -0.30402],
6342
[0.19403, 2.8403],
6343
[-0.50804, 0.29204],
6344
[-0.4, 0.]
6345
]),
6346
index=price_na.index,
6347
columns=pd.Index(['first', 'second'], dtype='object', name='group')
6348
)
6349
pd.testing.assert_frame_equal(
6350
pf.cash_flow(group_by=group_by),
6351
result
6352
)
6353
pd.testing.assert_frame_equal(
6354
pf_grouped.cash_flow(),
6355
result
6356
)
6357
pd.testing.assert_frame_equal(
6358
pf_shared.cash_flow(),
6359
result
6360
)
6361
6362
def test_init_cash(self):
6363
pd.testing.assert_series_equal(
6364
pf.init_cash,
6365
pd.Series(np.array([100., 100., 100.]), index=price_na.columns).rename('init_cash')
6366
)
6367
pd.testing.assert_series_equal(
6368
pf_grouped.get_init_cash(group_by=False),
6369
pd.Series(np.array([100., 100., 100.]), index=price_na.columns).rename('init_cash')
6370
)
6371
pd.testing.assert_series_equal(
6372
pf_shared.get_init_cash(group_by=False),
6373
pd.Series(np.array([200., 200., 100.]), index=price_na.columns).rename('init_cash')
6374
)
6375
result = pd.Series(
6376
np.array([200., 100.]),
6377
pd.Index(['first', 'second'], dtype='object', name='group')
6378
).rename('init_cash')
6379
pd.testing.assert_series_equal(
6380
pf.get_init_cash(group_by=group_by),
6381
result
6382
)
6383
pd.testing.assert_series_equal(
6384
pf_grouped.init_cash,
6385
result
6386
)
6387
pd.testing.assert_series_equal(
6388
pf_shared.init_cash,
6389
result
6390
)
6391
pd.testing.assert_series_equal(
6392
vbt.Portfolio.from_orders(
6393
price_na, 1000., init_cash=InitCashMode.Auto, group_by=None).init_cash,
6394
pd.Series(
6395
np.array([14000., 12000., 10000.]),
6396
index=price_na.columns
6397
).rename('init_cash')
6398
)
6399
pd.testing.assert_series_equal(
6400
vbt.Portfolio.from_orders(
6401
price_na, 1000., init_cash=InitCashMode.Auto, group_by=group_by).init_cash,
6402
pd.Series(
6403
np.array([26000.0, 10000.0]),
6404
index=pd.Index(['first', 'second'], dtype='object', name='group')
6405
).rename('init_cash')
6406
)
6407
pd.testing.assert_series_equal(
6408
vbt.Portfolio.from_orders(
6409
price_na, 1000., init_cash=InitCashMode.Auto, group_by=group_by, cash_sharing=True).init_cash,
6410
pd.Series(
6411
np.array([26000.0, 10000.0]),
6412
index=pd.Index(['first', 'second'], dtype='object', name='group')
6413
).rename('init_cash')
6414
)
6415
pd.testing.assert_series_equal(
6416
vbt.Portfolio.from_orders(
6417
price_na, 1000., init_cash=InitCashMode.AutoAlign, group_by=None).init_cash,
6418
pd.Series(
6419
np.array([14000., 14000., 14000.]),
6420
index=price_na.columns
6421
).rename('init_cash')
6422
)
6423
pd.testing.assert_series_equal(
6424
vbt.Portfolio.from_orders(
6425
price_na, 1000., init_cash=InitCashMode.AutoAlign, group_by=group_by).init_cash,
6426
pd.Series(
6427
np.array([26000.0, 26000.0]),
6428
index=pd.Index(['first', 'second'], dtype='object', name='group')
6429
).rename('init_cash')
6430
)
6431
pd.testing.assert_series_equal(
6432
vbt.Portfolio.from_orders(
6433
price_na, 1000., init_cash=InitCashMode.AutoAlign, group_by=group_by, cash_sharing=True).init_cash,
6434
pd.Series(
6435
np.array([26000.0, 26000.0]),
6436
index=pd.Index(['first', 'second'], dtype='object', name='group')
6437
).rename('init_cash')
6438
)
6439
6440
def test_cash(self):
6441
pd.testing.assert_frame_equal(
6442
pf.cash(free=True),
6443
pd.DataFrame(
6444
np.array([
6445
[100.0, 98.9001, 98.8799],
6446
[99.69598, 98.60011999999999, 98.57588000000001],
6447
[99.89001, 98.60011999999999, 101.41618000000001],
6448
[99.89001, 98.30807999999999, 101.70822000000001],
6449
[94.68951, 93.20857999999998, 101.70822000000001]
6450
]),
6451
index=price_na.index,
6452
columns=price_na.columns
6453
)
6454
)
6455
result = pd.DataFrame(
6456
np.array([
6457
[100., 100.8801, 98.8799],
6458
[99.69598, 100.97612, 98.57588],
6459
[99.89001, 100.97612, 101.41618],
6460
[99.89001, 100.46808, 101.70822],
6461
[94.68951, 105.26858, 101.70822]
6462
]),
6463
index=price_na.index,
6464
columns=price_na.columns
6465
)
6466
pd.testing.assert_frame_equal(
6467
pf.cash(),
6468
result
6469
)
6470
pd.testing.assert_frame_equal(
6471
pf_grouped.cash(group_by=False),
6472
result
6473
)
6474
pd.testing.assert_frame_equal(
6475
pf_shared.cash(group_by=False),
6476
pd.DataFrame(
6477
np.array([
6478
[200., 200.8801, 98.8799],
6479
[199.69598, 200.97612, 98.57588],
6480
[199.89001, 200.97612, 101.41618],
6481
[199.89001, 200.46808, 101.70822],
6482
[194.68951, 205.26858, 101.70822]
6483
]),
6484
index=price_na.index,
6485
columns=price_na.columns
6486
)
6487
)
6488
pd.testing.assert_frame_equal(
6489
pf_shared.cash(group_by=False, in_sim_order=True),
6490
pd.DataFrame(
6491
np.array([
6492
[200.8801, 200.8801, 98.8799],
6493
[200.6721, 200.97612, 98.57588000000001],
6494
[200.86613, 200.6721, 101.41618000000001],
6495
[200.35809, 200.35809, 101.70822000000001],
6496
[199.95809, 205.15859, 101.70822000000001]
6497
]),
6498
index=price_na.index,
6499
columns=price_na.columns
6500
)
6501
)
6502
result = pd.DataFrame(
6503
np.array([
6504
[200.8801, 98.8799],
6505
[200.6721, 98.57588],
6506
[200.86613, 101.41618],
6507
[200.35809, 101.70822],
6508
[199.95809, 101.70822]
6509
]),
6510
index=price_na.index,
6511
columns=pd.Index(['first', 'second'], dtype='object', name='group')
6512
)
6513
pd.testing.assert_frame_equal(
6514
pf.cash(group_by=group_by),
6515
result
6516
)
6517
pd.testing.assert_frame_equal(
6518
pf_grouped.cash(),
6519
result
6520
)
6521
pd.testing.assert_frame_equal(
6522
pf_shared.cash(),
6523
result
6524
)
6525
6526
def test_asset_value(self):
6527
pd.testing.assert_frame_equal(
6528
pf.asset_value(direction='longonly'),
6529
pd.DataFrame(
6530
np.array([
6531
[0., 0., 1.],
6532
[0.2, 0., 2.2],
6533
[0., 0., 0.3],
6534
[0., 0., 0.],
6535
[5., 0., 0.]
6536
]),
6537
index=price_na.index,
6538
columns=price_na.columns
6539
)
6540
)
6541
pd.testing.assert_frame_equal(
6542
pf.asset_value(direction='shortonly'),
6543
pd.DataFrame(
6544
np.array([
6545
[0., 1., 0.],
6546
[0., 2.2, 0.],
6547
[0., 2.2, 0.],
6548
[0., 4., 0.],
6549
[0., 10., 0.]
6550
]),
6551
index=price_na.index,
6552
columns=price_na.columns
6553
)
6554
)
6555
result = pd.DataFrame(
6556
np.array([
6557
[0., -1., 1.],
6558
[0.2, -2.2, 2.2],
6559
[0., -2.2, 0.3],
6560
[0., -4., 0.],
6561
[5., -10., 0.]
6562
]),
6563
index=price_na.index,
6564
columns=price_na.columns
6565
)
6566
pd.testing.assert_frame_equal(
6567
pf.asset_value(),
6568
result
6569
)
6570
pd.testing.assert_frame_equal(
6571
pf_grouped.asset_value(group_by=False),
6572
result
6573
)
6574
pd.testing.assert_frame_equal(
6575
pf_shared.asset_value(group_by=False),
6576
result
6577
)
6578
result = pd.DataFrame(
6579
np.array([
6580
[-1., 1.],
6581
[-2., 2.2],
6582
[-2.2, 0.3],
6583
[-4., 0.],
6584
[-5., 0.]
6585
]),
6586
index=price_na.index,
6587
columns=pd.Index(['first', 'second'], dtype='object', name='group')
6588
)
6589
pd.testing.assert_frame_equal(
6590
pf.asset_value(group_by=group_by),
6591
result
6592
)
6593
pd.testing.assert_frame_equal(
6594
pf_grouped.asset_value(),
6595
result
6596
)
6597
pd.testing.assert_frame_equal(
6598
pf_shared.asset_value(),
6599
result
6600
)
6601
6602
def test_gross_exposure(self):
6603
pd.testing.assert_frame_equal(
6604
pf.gross_exposure(direction='longonly'),
6605
pd.DataFrame(
6606
np.array([
6607
[0., 0., 0.01001202],
6608
[0.00200208, 0., 0.02183062],
6609
[0., 0., 0.00294938],
6610
[0., 0., 0.],
6611
[0.05015573, 0., 0.]
6612
]),
6613
index=price_na.index,
6614
columns=price_na.columns
6615
)
6616
)
6617
pd.testing.assert_frame_equal(
6618
pf.gross_exposure(direction='shortonly'),
6619
pd.DataFrame(
6620
np.array([
6621
[0.0, 0.01000999998999, 0.0],
6622
[0.0, 0.021825370842812494, 0.0],
6623
[0.0, 0.021825370842812494, 0.0],
6624
[0.0, 0.03909759620159034, 0.0],
6625
[0.0, 0.09689116931945001, 0.0]
6626
]),
6627
index=price_na.index,
6628
columns=price_na.columns
6629
)
6630
)
6631
result = pd.DataFrame(
6632
np.array([
6633
[0.0, -0.010214494162927312, 0.010012024441354066],
6634
[0.00200208256628545, -0.022821548354919067, 0.021830620581035857],
6635
[0.0, -0.022821548354919067, 0.002949383274126105],
6636
[0.0, -0.04241418126633477, 0.0],
6637
[0.050155728521486365, -0.12017991413866216, 0.0]
6638
]),
6639
index=price_na.index,
6640
columns=price_na.columns
6641
)
6642
pd.testing.assert_frame_equal(
6643
pf.gross_exposure(),
6644
result
6645
)
6646
pd.testing.assert_frame_equal(
6647
pf_grouped.gross_exposure(group_by=False),
6648
result
6649
)
6650
pd.testing.assert_frame_equal(
6651
pf_shared.gross_exposure(group_by=False),
6652
pd.DataFrame(
6653
np.array([
6654
[0.0, -0.00505305454620791, 0.010012024441354066],
6655
[0.0010005203706447724, -0.011201622483733716, 0.021830620581035857],
6656
[0.0, -0.011201622483733716, 0.002949383274126105],
6657
[0.0, -0.020585865497718882, 0.0],
6658
[0.025038871596209537, -0.0545825965137659, 0.0]
6659
]),
6660
index=price_na.index,
6661
columns=price_na.columns
6662
)
6663
)
6664
result = pd.DataFrame(
6665
np.array([
6666
[-0.00505305454620791, 0.010012024441354066],
6667
[-0.010188689433972452, 0.021830620581035857],
6668
[-0.0112078992458765, 0.002949383274126105],
6669
[-0.02059752492931316, 0.0],
6670
[-0.027337628293439265, 0.0]
6671
]),
6672
index=price_na.index,
6673
columns=pd.Index(['first', 'second'], dtype='object', name='group')
6674
)
6675
pd.testing.assert_frame_equal(
6676
pf.gross_exposure(group_by=group_by),
6677
result
6678
)
6679
pd.testing.assert_frame_equal(
6680
pf_grouped.gross_exposure(),
6681
result
6682
)
6683
pd.testing.assert_frame_equal(
6684
pf_shared.gross_exposure(),
6685
result
6686
)
6687
6688
def test_net_exposure(self):
6689
result = pd.DataFrame(
6690
np.array([
6691
[0.0, -0.01000999998999, 0.010012024441354066],
6692
[0.00200208256628545, -0.021825370842812494, 0.021830620581035857],
6693
[0.0, -0.021825370842812494, 0.002949383274126105],
6694
[0.0, -0.03909759620159034, 0.0],
6695
[0.050155728521486365, -0.09689116931945001, 0.0]
6696
]),
6697
index=price_na.index,
6698
columns=price_na.columns
6699
)
6700
pd.testing.assert_frame_equal(
6701
pf.net_exposure(),
6702
result
6703
)
6704
pd.testing.assert_frame_equal(
6705
pf_grouped.net_exposure(group_by=False),
6706
result
6707
)
6708
pd.testing.assert_frame_equal(
6709
pf_shared.net_exposure(group_by=False),
6710
pd.DataFrame(
6711
np.array([
6712
[0.0, -0.005002498748124688, 0.010012024441354066],
6713
[0.0010005203706447724, -0.010956168751293576, 0.021830620581035857],
6714
[0.0, -0.010956168751293576, 0.002949383274126105],
6715
[0.0, -0.019771825228137207, 0.0],
6716
[0.025038871596209537, -0.049210520540028384, 0.0]
6717
]),
6718
index=price_na.index,
6719
columns=price_na.columns
6720
)
6721
)
6722
result = pd.DataFrame(
6723
np.array([
6724
[-0.005002498748124688, 0.010012024441354066],
6725
[-0.009965205542937988, 0.021830620581035857],
6726
[-0.010962173376438594, 0.002949383274126105],
6727
[-0.019782580537729116, 0.0],
6728
[-0.0246106361476199, 0.0]
6729
]),
6730
index=price_na.index,
6731
columns=pd.Index(['first', 'second'], dtype='object', name='group')
6732
)
6733
pd.testing.assert_frame_equal(
6734
pf.net_exposure(group_by=group_by),
6735
result
6736
)
6737
pd.testing.assert_frame_equal(
6738
pf_grouped.net_exposure(),
6739
result
6740
)
6741
pd.testing.assert_frame_equal(
6742
pf_shared.net_exposure(),
6743
result
6744
)
6745
6746
def test_value(self):
6747
result = pd.DataFrame(
6748
np.array([
6749
[100., 99.8801, 99.8799],
6750
[99.89598, 98.77612, 100.77588],
6751
[99.89001, 98.77612, 101.71618],
6752
[99.89001, 96.46808, 101.70822],
6753
[99.68951, 95.26858, 101.70822]
6754
]),
6755
index=price_na.index,
6756
columns=price_na.columns
6757
)
6758
pd.testing.assert_frame_equal(
6759
pf.value(),
6760
result
6761
)
6762
pd.testing.assert_frame_equal(
6763
pf_grouped.value(group_by=False),
6764
result
6765
)
6766
pd.testing.assert_frame_equal(
6767
pf_shared.value(group_by=False),
6768
pd.DataFrame(
6769
np.array([
6770
[200., 199.8801, 99.8799],
6771
[199.89598, 198.77612, 100.77588],
6772
[199.89001, 198.77612, 101.71618],
6773
[199.89001, 196.46808, 101.70822],
6774
[199.68951, 195.26858, 101.70822]
6775
]),
6776
index=price_na.index,
6777
columns=price_na.columns
6778
)
6779
)
6780
pd.testing.assert_frame_equal(
6781
pf_shared.value(group_by=False, in_sim_order=True),
6782
pd.DataFrame(
6783
np.array([
6784
[199.8801, 199.8801, 99.8799],
6785
[198.6721, 198.77612000000002, 100.77588000000002],
6786
[198.66613, 198.6721, 101.71618000000001],
6787
[196.35809, 196.35809, 101.70822000000001],
6788
[194.95809, 195.15859, 101.70822000000001]
6789
]),
6790
index=price_na.index,
6791
columns=price_na.columns
6792
)
6793
)
6794
result = pd.DataFrame(
6795
np.array([
6796
[199.8801, 99.8799],
6797
[198.6721, 100.77588],
6798
[198.66613, 101.71618],
6799
[196.35809, 101.70822],
6800
[194.95809, 101.70822]
6801
]),
6802
index=price_na.index,
6803
columns=pd.Index(['first', 'second'], dtype='object', name='group')
6804
)
6805
pd.testing.assert_frame_equal(
6806
pf.value(group_by=group_by),
6807
result
6808
)
6809
pd.testing.assert_frame_equal(
6810
pf_grouped.value(),
6811
result
6812
)
6813
pd.testing.assert_frame_equal(
6814
pf_shared.value(),
6815
result
6816
)
6817
6818
def test_total_profit(self):
6819
result = pd.Series(
6820
np.array([-0.31049, -4.73142, 1.70822]),
6821
index=price_na.columns
6822
).rename('total_profit')
6823
pd.testing.assert_series_equal(
6824
pf.total_profit(),
6825
result
6826
)
6827
pd.testing.assert_series_equal(
6828
pf_grouped.total_profit(group_by=False),
6829
result
6830
)
6831
pd.testing.assert_series_equal(
6832
pf_shared.total_profit(group_by=False),
6833
result
6834
)
6835
result = pd.Series(
6836
np.array([-5.04191, 1.70822]),
6837
index=pd.Index(['first', 'second'], dtype='object', name='group')
6838
).rename('total_profit')
6839
pd.testing.assert_series_equal(
6840
pf.total_profit(group_by=group_by),
6841
result
6842
)
6843
pd.testing.assert_series_equal(
6844
pf_grouped.total_profit(),
6845
result
6846
)
6847
pd.testing.assert_series_equal(
6848
pf_shared.total_profit(),
6849
result
6850
)
6851
6852
def test_final_value(self):
6853
result = pd.Series(
6854
np.array([99.68951, 95.26858, 101.70822]),
6855
index=price_na.columns
6856
).rename('final_value')
6857
pd.testing.assert_series_equal(
6858
pf.final_value(),
6859
result
6860
)
6861
pd.testing.assert_series_equal(
6862
pf_grouped.final_value(group_by=False),
6863
result
6864
)
6865
pd.testing.assert_series_equal(
6866
pf_shared.final_value(group_by=False),
6867
pd.Series(
6868
np.array([199.68951, 195.26858, 101.70822]),
6869
index=price_na.columns
6870
).rename('final_value')
6871
)
6872
result = pd.Series(
6873
np.array([194.95809, 101.70822]),
6874
index=pd.Index(['first', 'second'], dtype='object', name='group')
6875
).rename('final_value')
6876
pd.testing.assert_series_equal(
6877
pf.final_value(group_by=group_by),
6878
result
6879
)
6880
pd.testing.assert_series_equal(
6881
pf_grouped.final_value(),
6882
result
6883
)
6884
pd.testing.assert_series_equal(
6885
pf_shared.final_value(),
6886
result
6887
)
6888
6889
def test_total_return(self):
6890
result = pd.Series(
6891
np.array([-0.0031049, -0.0473142, 0.0170822]),
6892
index=price_na.columns
6893
).rename('total_return')
6894
pd.testing.assert_series_equal(
6895
pf.total_return(),
6896
result
6897
)
6898
pd.testing.assert_series_equal(
6899
pf_grouped.total_return(group_by=False),
6900
result
6901
)
6902
pd.testing.assert_series_equal(
6903
pf_shared.total_return(group_by=False),
6904
pd.Series(
6905
np.array([-0.00155245, -0.0236571, 0.0170822]),
6906
index=price_na.columns
6907
).rename('total_return')
6908
)
6909
result = pd.Series(
6910
np.array([-0.02520955, 0.0170822]),
6911
index=pd.Index(['first', 'second'], dtype='object', name='group')
6912
).rename('total_return')
6913
pd.testing.assert_series_equal(
6914
pf.total_return(group_by=group_by),
6915
result
6916
)
6917
pd.testing.assert_series_equal(
6918
pf_grouped.total_return(),
6919
result
6920
)
6921
pd.testing.assert_series_equal(
6922
pf_shared.total_return(),
6923
result
6924
)
6925
6926
def test_returns(self):
6927
result = pd.DataFrame(
6928
np.array([
6929
[0.00000000e+00, -1.19900000e-03, -1.20100000e-03],
6930
[-1.04020000e-03, -1.10530526e-02, 8.97057366e-03],
6931
[-5.97621646e-05, 0.0, 9.33060570e-03],
6932
[0.00000000e+00, -0.023366376407576966, -7.82569695e-05],
6933
[-2.00720773e-03, -1.24341648e-02, 0.00000000e+00]
6934
]),
6935
index=price_na.index,
6936
columns=price_na.columns
6937
)
6938
pd.testing.assert_frame_equal(
6939
pf.returns(),
6940
result
6941
)
6942
pd.testing.assert_frame_equal(
6943
pf_grouped.returns(group_by=False),
6944
result
6945
)
6946
pd.testing.assert_frame_equal(
6947
pf_shared.returns(group_by=False),
6948
pd.DataFrame(
6949
np.array([
6950
[0.00000000e+00, -5.99500000e-04, -1.20100000e-03],
6951
[-5.20100000e-04, -5.52321117e-03, 8.97057366e-03],
6952
[-2.98655331e-05, 0.0, 9.33060570e-03],
6953
[0.00000000e+00, -0.011611253907159497, -7.82569695e-05],
6954
[-1.00305163e-03, -6.10531746e-03, 0.00000000e+00]
6955
]),
6956
index=price_na.index,
6957
columns=price_na.columns
6958
)
6959
)
6960
pd.testing.assert_frame_equal(
6961
pf_shared.returns(group_by=False, in_sim_order=True),
6962
pd.DataFrame(
6963
np.array([
6964
[0.0, -0.0005995000000000062, -1.20100000e-03],
6965
[-0.0005233022960706736, -0.005523211165093367, 8.97057366e-03],
6966
[-3.0049513746473233e-05, 0.0, 9.33060570e-03],
6967
[0.0, -0.011617682390048093, -7.82569695e-05],
6968
[-0.0010273695869600474, -0.0061087373583639994, 0.00000000e+00]
6969
]),
6970
index=price_na.index,
6971
columns=price_na.columns
6972
)
6973
)
6974
result = pd.DataFrame(
6975
np.array([
6976
[-5.99500000e-04, -1.20100000e-03],
6977
[-6.04362315e-03, 8.97057366e-03],
6978
[-3.0049513746473233e-05, 9.33060570e-03],
6979
[-0.011617682390048093, -7.82569695e-05],
6980
[-7.12983101e-03, 0.00000000e+00]
6981
]),
6982
index=price_na.index,
6983
columns=pd.Index(['first', 'second'], dtype='object', name='group')
6984
)
6985
pd.testing.assert_frame_equal(
6986
pf.returns(group_by=group_by),
6987
result
6988
)
6989
pd.testing.assert_frame_equal(
6990
pf_grouped.returns(),
6991
result
6992
)
6993
pd.testing.assert_frame_equal(
6994
pf_shared.returns(),
6995
result
6996
)
6997
6998
def test_asset_returns(self):
6999
result = pd.DataFrame(
7000
np.array([
7001
[0., -np.inf, -np.inf],
7002
[-np.inf, -1.10398, 0.89598],
7003
[-0.02985, 0.0, 0.42740909],
7004
[0., -1.0491090909090908, -0.02653333],
7005
[-np.inf, -0.299875, 0.]
7006
]),
7007
index=price_na.index,
7008
columns=price_na.columns
7009
)
7010
pd.testing.assert_frame_equal(
7011
pf.asset_returns(),
7012
result
7013
)
7014
pd.testing.assert_frame_equal(
7015
pf_grouped.asset_returns(group_by=False),
7016
result
7017
)
7018
pd.testing.assert_frame_equal(
7019
pf_shared.asset_returns(group_by=False),
7020
result
7021
)
7022
result = pd.DataFrame(
7023
np.array([
7024
[-np.inf, -np.inf],
7025
[-1.208, 0.89598],
7026
[-0.0029850000000000154, 0.42740909],
7027
[-1.0491090909090908, -0.02653333],
7028
[-0.35, 0.]
7029
]),
7030
index=price_na.index,
7031
columns=pd.Index(['first', 'second'], dtype='object', name='group')
7032
)
7033
pd.testing.assert_frame_equal(
7034
pf.asset_returns(group_by=group_by),
7035
result
7036
)
7037
pd.testing.assert_frame_equal(
7038
pf_grouped.asset_returns(),
7039
result
7040
)
7041
pd.testing.assert_frame_equal(
7042
pf_shared.asset_returns(),
7043
result
7044
)
7045
7046
def test_benchmark_value(self):
7047
result = pd.DataFrame(
7048
np.array([
7049
[100., 100., 100.],
7050
[100., 200., 200.],
7051
[150., 200., 300.],
7052
[200., 400., 400.],
7053
[250., 500., 400.]
7054
]),
7055
index=price_na.index,
7056
columns=price_na.columns
7057
)
7058
pd.testing.assert_frame_equal(
7059
pf.benchmark_value(),
7060
result
7061
)
7062
pd.testing.assert_frame_equal(
7063
pf_grouped.benchmark_value(group_by=False),
7064
result
7065
)
7066
pd.testing.assert_frame_equal(
7067
pf_shared.benchmark_value(group_by=False),
7068
pd.DataFrame(
7069
np.array([
7070
[200., 200., 100.],
7071
[200., 400., 200.],
7072
[300., 400., 300.],
7073
[400., 800., 400.],
7074
[500., 1000., 400.]
7075
]),
7076
index=price_na.index,
7077
columns=price_na.columns
7078
)
7079
)
7080
result = pd.DataFrame(
7081
np.array([
7082
[200., 100.],
7083
[300., 200.],
7084
[350., 300.],
7085
[600., 400.],
7086
[750., 400.]
7087
]),
7088
index=price_na.index,
7089
columns=pd.Index(['first', 'second'], dtype='object', name='group')
7090
)
7091
pd.testing.assert_frame_equal(
7092
pf.benchmark_value(group_by=group_by),
7093
result
7094
)
7095
pd.testing.assert_frame_equal(
7096
pf_grouped.benchmark_value(),
7097
result
7098
)
7099
pd.testing.assert_frame_equal(
7100
pf_shared.benchmark_value(),
7101
result
7102
)
7103
7104
def test_benchmark_returns(self):
7105
result = pd.DataFrame(
7106
np.array([
7107
[0., 0., 0.],
7108
[0., 1., 1.],
7109
[0.5, 0., 0.5],
7110
[0.33333333, 1., 0.33333333],
7111
[0.25, 0.25, 0.]
7112
]),
7113
index=price_na.index,
7114
columns=price_na.columns
7115
)
7116
pd.testing.assert_frame_equal(
7117
pf.benchmark_returns(),
7118
result
7119
)
7120
pd.testing.assert_frame_equal(
7121
pf_grouped.benchmark_returns(group_by=False),
7122
result
7123
)
7124
pd.testing.assert_frame_equal(
7125
pf_shared.benchmark_returns(group_by=False),
7126
result
7127
)
7128
result = pd.DataFrame(
7129
np.array([
7130
[0., 0.],
7131
[0.5, 1.],
7132
[0.16666667, 0.5],
7133
[0.71428571, 0.33333333],
7134
[0.25, 0.]
7135
]),
7136
index=price_na.index,
7137
columns=pd.Index(['first', 'second'], dtype='object', name='group')
7138
)
7139
pd.testing.assert_frame_equal(
7140
pf.benchmark_returns(group_by=group_by),
7141
result
7142
)
7143
pd.testing.assert_frame_equal(
7144
pf_grouped.benchmark_returns(),
7145
result
7146
)
7147
pd.testing.assert_frame_equal(
7148
pf_shared.benchmark_returns(),
7149
result
7150
)
7151
7152
def test_total_benchmark_return(self):
7153
result = pd.Series(
7154
np.array([1.5, 4., 3.]),
7155
index=price_na.columns
7156
).rename('total_benchmark_return')
7157
pd.testing.assert_series_equal(
7158
pf.total_benchmark_return(),
7159
result
7160
)
7161
pd.testing.assert_series_equal(
7162
pf_grouped.total_benchmark_return(group_by=False),
7163
result
7164
)
7165
pd.testing.assert_series_equal(
7166
pf_shared.total_benchmark_return(group_by=False),
7167
result
7168
)
7169
result = pd.Series(
7170
np.array([2.75, 3.]),
7171
index=pd.Index(['first', 'second'], dtype='object', name='group')
7172
).rename('total_benchmark_return')
7173
pd.testing.assert_series_equal(
7174
pf.total_benchmark_return(group_by=group_by),
7175
result
7176
)
7177
pd.testing.assert_series_equal(
7178
pf_grouped.total_benchmark_return(),
7179
result
7180
)
7181
pd.testing.assert_series_equal(
7182
pf_shared.total_benchmark_return(),
7183
result
7184
)
7185
7186
def test_return_method(self):
7187
pd.testing.assert_frame_equal(
7188
pf_shared.cumulative_returns(),
7189
pd.DataFrame(
7190
np.array([
7191
[-0.000599499999999975, -0.0012009999999998966],
7192
[-0.006639499999999909, 0.007758800000000177],
7193
[-0.006669349999999907, 0.017161800000000005],
7194
[-0.01820955000000002, 0.017082199999999936],
7195
[-0.025209550000000136, 0.017082199999999936]
7196
]),
7197
index=price_na.index,
7198
columns=pd.Index(['first', 'second'], dtype='object', name='group')
7199
)
7200
)
7201
pd.testing.assert_frame_equal(
7202
pf_shared.cumulative_returns(group_by=False),
7203
pd.DataFrame(
7204
np.array([
7205
[0.0, -0.000599499999999975, -0.0012009999999998966],
7206
[-0.0005201000000001343, -0.006119399999999886, 0.007758800000000177],
7207
[-0.0005499500000001323, -0.006119399999999886, 0.017161800000000005],
7208
[-0.0005499500000001323, -0.017659599999999886, 0.017082199999999936],
7209
[-0.0015524500000001495, -0.023657099999999875, 0.017082199999999936]
7210
]),
7211
index=price_na.index,
7212
columns=price_na.columns
7213
)
7214
)
7215
pd.testing.assert_series_equal(
7216
pf_shared.sharpe_ratio(),
7217
pd.Series(
7218
np.array([-20.095906945591288, 12.345065267401496]),
7219
index=pd.Index(['first', 'second'], dtype='object', name='group')
7220
).rename('sharpe_ratio')
7221
)
7222
pd.testing.assert_series_equal(
7223
pf_shared.sharpe_ratio(risk_free=0.01),
7224
pd.Series(
7225
np.array([-59.62258787402645, -23.91718815937344]),
7226
index=pd.Index(['first', 'second'], dtype='object', name='group')
7227
).rename('sharpe_ratio')
7228
)
7229
pd.testing.assert_series_equal(
7230
pf_shared.sharpe_ratio(year_freq='365D'),
7231
pd.Series(
7232
np.array([-20.095906945591288, 12.345065267401496]),
7233
index=pd.Index(['first', 'second'], dtype='object', name='group')
7234
).rename('sharpe_ratio')
7235
)
7236
pd.testing.assert_series_equal(
7237
pf_shared.sharpe_ratio(group_by=False),
7238
pd.Series(
7239
np.array([-13.30950646054953, -19.278625117344564, 12.345065267401496]),
7240
index=price_na.columns
7241
).rename('sharpe_ratio')
7242
)
7243
pd.testing.assert_series_equal(
7244
pf_shared.information_ratio(group_by=False),
7245
pd.Series(
7246
np.array([-0.9988561334618041, -0.8809478746008806, -0.884780642352239]),
7247
index=price_na.columns
7248
).rename('information_ratio')
7249
)
7250
with pytest.raises(Exception):
7251
_ = pf_shared.information_ratio(pf_shared.benchmark_returns(group_by=False) * 2)
7252
7253
def test_stats(self):
7254
stats_index = pd.Index([
7255
'Start', 'End', 'Period', 'Start Value', 'End Value',
7256
'Total Return [%]', 'Benchmark Return [%]', 'Max Gross Exposure [%]',
7257
'Total Fees Paid', 'Max Drawdown [%]', 'Max Drawdown Duration',
7258
'Total Trades', 'Total Closed Trades', 'Total Open Trades',
7259
'Open Trade PnL', 'Win Rate [%]', 'Best Trade [%]', 'Worst Trade [%]',
7260
'Avg Winning Trade [%]', 'Avg Losing Trade [%]',
7261
'Avg Winning Trade Duration', 'Avg Losing Trade Duration',
7262
'Profit Factor', 'Expectancy', 'Sharpe Ratio', 'Calmar Ratio',
7263
'Omega Ratio', 'Sortino Ratio'
7264
], dtype='object')
7265
pd.testing.assert_series_equal(
7266
pf.stats(),
7267
pd.Series(
7268
np.array([
7269
pd.Timestamp('2020-01-01 00:00:00'), pd.Timestamp('2020-01-05 00:00:00'),
7270
pd.Timedelta('5 days 00:00:00'), 100.0, 98.88877000000001, -1.11123, 283.3333333333333,
7271
2.05906183131983, 0.42223000000000005, 1.6451238489727062, pd.Timedelta('3 days 08:00:00'),
7272
2.0, 1.3333333333333333, 0.6666666666666666, -1.5042060606060605, 33.333333333333336,
7273
-98.38058805880588, -100.8038553855386, 143.91625412541256, -221.34645964596464,
7274
pd.Timedelta('2 days 12:00:00'), pd.Timedelta('2 days 00:00:00'), np.inf, 0.10827272727272726,
7275
-6.751008013903537, 10378.930331014584, 4.768700318817701, 31.599760994679134
7276
]),
7277
index=stats_index,
7278
name='agg_func_mean')
7279
)
7280
pd.testing.assert_series_equal(
7281
pf.stats(column='a'),
7282
pd.Series(
7283
np.array([
7284
pd.Timestamp('2020-01-01 00:00:00'), pd.Timestamp('2020-01-05 00:00:00'),
7285
pd.Timedelta('5 days 00:00:00'), 100.0, 99.68951, -0.3104899999999997, 150.0,
7286
5.015572852148637, 0.35549, 0.3104900000000015, pd.Timedelta('4 days 00:00:00'),
7287
2, 1, 1, -0.20049999999999982, 0.0, -54.450495049504966, -54.450495049504966,
7288
np.nan, -54.450495049504966, pd.NaT, pd.Timedelta('1 days 00:00:00'), 0.0,
7289
-0.10999000000000003, -13.30804491478906, -65.40868619923044, 0.0, -11.738864633265454
7290
]),
7291
index=stats_index,
7292
name='a')
7293
)
7294
pd.testing.assert_series_equal(
7295
pf.stats(column='a', settings=dict(freq='10 days', year_freq='200 days')),
7296
pd.Series(
7297
np.array([
7298
pd.Timestamp('2020-01-01 00:00:00'), pd.Timestamp('2020-01-05 00:00:00'),
7299
pd.Timedelta('50 days 00:00:00'), 100.0, 99.68951, -0.3104899999999997, 150.0,
7300
5.015572852148637, 0.35549, 0.3104900000000015, pd.Timedelta('40 days 00:00:00'),
7301
2, 1, 1, -0.20049999999999982, 0.0, -54.450495049504966, -54.450495049504966,
7302
np.nan, -54.450495049504966, pd.NaT, pd.Timedelta('10 days 00:00:00'), 0.0, -0.10999000000000003,
7303
-3.1151776875290866, -3.981409131683691, 0.0, -2.7478603669149457
7304
]),
7305
index=stats_index,
7306
name='a')
7307
)
7308
pd.testing.assert_series_equal(
7309
pf.stats(column='a', settings=dict(trade_type='positions')),
7310
pd.Series(
7311
np.array([
7312
pd.Timestamp('2020-01-01 00:00:00'), pd.Timestamp('2020-01-05 00:00:00'),
7313
pd.Timedelta('5 days 00:00:00'), 100.0, 99.68951, -0.3104899999999997, 150.0,
7314
5.015572852148637, 0.35549, 0.3104900000000015, pd.Timedelta('4 days 00:00:00'),
7315
2, 1, 1, -0.20049999999999982, 0.0, -54.450495049504966, -54.450495049504966,
7316
np.nan, -54.450495049504966, pd.NaT, pd.Timedelta('1 days 00:00:00'), 0.0,
7317
-0.10999000000000003, -13.30804491478906, -65.40868619923044, 0.0, -11.738864633265454
7318
]),
7319
index=pd.Index([
7320
'Start', 'End', 'Period', 'Start Value', 'End Value',
7321
'Total Return [%]', 'Benchmark Return [%]', 'Max Gross Exposure [%]',
7322
'Total Fees Paid', 'Max Drawdown [%]', 'Max Drawdown Duration',
7323
'Total Trades', 'Total Closed Trades', 'Total Open Trades',
7324
'Open Trade PnL', 'Win Rate [%]', 'Best Trade [%]',
7325
'Worst Trade [%]', 'Avg Winning Trade [%]',
7326
'Avg Losing Trade [%]', 'Avg Winning Trade Duration',
7327
'Avg Losing Trade Duration', 'Profit Factor', 'Expectancy',
7328
'Sharpe Ratio', 'Calmar Ratio', 'Omega Ratio', 'Sortino Ratio'
7329
], dtype='object'),
7330
name='a')
7331
)
7332
pd.testing.assert_series_equal(
7333
pf.stats(column='a', settings=dict(required_return=0.1, risk_free=0.01)),
7334
pd.Series(
7335
np.array([
7336
pd.Timestamp('2020-01-01 00:00:00'), pd.Timestamp('2020-01-05 00:00:00'),
7337
pd.Timedelta('5 days 00:00:00'), 100.0, 99.68951, -0.3104899999999997, 150.0,
7338
5.015572852148637, 0.35549, 0.3104900000000015, pd.Timedelta('4 days 00:00:00'),
7339
2, 1, 1, -0.20049999999999982, 0.0, -54.450495049504966, -54.450495049504966,
7340
np.nan, -54.450495049504966, pd.NaT, pd.Timedelta('1 days 00:00:00'), 0.0,
7341
-0.10999000000000003, -227.45862849586334, -65.40868619923044, 0.0, -19.104372472268942
7342
]),
7343
index=stats_index,
7344
name='a')
7345
)
7346
pd.testing.assert_series_equal(
7347
pf.stats(column='a', settings=dict(use_asset_returns=True)),
7348
pd.Series(
7349
np.array([
7350
pd.Timestamp('2020-01-01 00:00:00'), pd.Timestamp('2020-01-05 00:00:00'),
7351
pd.Timedelta('5 days 00:00:00'), 100.0, 99.68951, -0.3104899999999997,
7352
150.0, 5.015572852148637, 0.35549, 0.3104900000000015, pd.Timedelta('4 days 00:00:00'),
7353
2, 1, 1, -0.20049999999999982, 0.0, -54.450495049504966, -54.450495049504966, np.nan,
7354
-54.450495049504966, pd.NaT, pd.Timedelta('1 days 00:00:00'), 0.0, -0.10999000000000003,
7355
np.nan, np.nan, 0.0, np.nan
7356
]),
7357
index=stats_index,
7358
name='a')
7359
)
7360
pd.testing.assert_series_equal(
7361
pf.stats(column='a', settings=dict(incl_open=True)),
7362
pd.Series(
7363
np.array([
7364
pd.Timestamp('2020-01-01 00:00:00'), pd.Timestamp('2020-01-05 00:00:00'),
7365
pd.Timedelta('5 days 00:00:00'), 100.0, 99.68951, -0.3104899999999997, 150.0,
7366
5.015572852148637, 0.35549, 0.3104900000000015, pd.Timedelta('4 days 00:00:00'),
7367
2, 1, 1, -0.20049999999999982, 0.0, -3.9702970297029667, -54.450495049504966,
7368
np.nan, -29.210396039603964, pd.NaT, pd.Timedelta('1 days 00:00:00'), 0.0,
7369
-0.1552449999999999, -13.30804491478906, -65.40868619923044, 0.0, -11.738864633265454
7370
]),
7371
index=stats_index,
7372
name='a')
7373
)
7374
pd.testing.assert_series_equal(
7375
pf_grouped.stats(column='first'),
7376
pd.Series(
7377
np.array([
7378
pd.Timestamp('2020-01-01 00:00:00'), pd.Timestamp('2020-01-05 00:00:00'),
7379
pd.Timedelta('5 days 00:00:00'), 200.0, 194.95809, -2.520955, 275.0, -0.505305454620791,
7380
0.82091, 2.46248125751388, pd.Timedelta('4 days 00:00:00'), 4, 2, 2, -4.512618181818182,
7381
0.0, -54.450495049504966, -388.2424242424243, np.nan, -221.34645964596461, pd.NaT,
7382
pd.Timedelta('2 days 00:00:00'), 0.0, -0.2646459090909091, -20.095906945591288,
7383
-34.312217430388344, 0.0, -14.554511690523578
7384
]),
7385
index=stats_index,
7386
name='first')
7387
)
7388
pd.testing.assert_series_equal(
7389
pf.stats(column='a', tags='trades and open and not closed', settings=dict(incl_open=True)),
7390
pd.Series(
7391
np.array([
7392
1, -0.20049999999999982
7393
]),
7394
index=pd.Index([
7395
'Total Open Trades', 'Open Trade PnL'
7396
], dtype='object'),
7397
name='a')
7398
)
7399
max_winning_streak = (
7400
'max_winning_streak',
7401
dict(
7402
title='Max Winning Streak',
7403
calc_func=lambda trades: trades.winning_streak.max(),
7404
resolve_trades=True
7405
)
7406
)
7407
pd.testing.assert_series_equal(
7408
pf.stats(column='a', metrics=max_winning_streak),
7409
pd.Series([0.0], index=['Max Winning Streak'], name='a')
7410
)
7411
max_winning_streak = (
7412
'max_winning_streak',
7413
dict(
7414
title='Max Winning Streak',
7415
calc_func=lambda self, group_by: self.get_trades(group_by=group_by).winning_streak.max()
7416
)
7417
)
7418
pd.testing.assert_series_equal(
7419
pf.stats(column='a', metrics=max_winning_streak),
7420
pd.Series([0.0], index=['Max Winning Streak'], name='a')
7421
)
7422
max_winning_streak = (
7423
'max_winning_streak',
7424
dict(
7425
title='Max Winning Streak',
7426
calc_func=lambda self, settings:
7427
self.get_trades(group_by=settings['group_by']).winning_streak.max(),
7428
resolve_calc_func=False
7429
)
7430
)
7431
pd.testing.assert_series_equal(
7432
pf.stats(column='a', metrics=max_winning_streak),
7433
pd.Series([0.0], index=['Max Winning Streak'], name='a')
7434
)
7435
vbt.settings.portfolio.stats['settings']['my_arg'] = 100
7436
my_arg_metric = ('my_arg_metric', dict(title='My Arg', calc_func=lambda my_arg: my_arg))
7437
pd.testing.assert_series_equal(
7438
pf.stats(my_arg_metric, column='a'),
7439
pd.Series([100], index=['My Arg'], name='a')
7440
)
7441
vbt.settings.portfolio.stats.reset()
7442
pd.testing.assert_series_equal(
7443
pf.stats(my_arg_metric, column='a', settings=dict(my_arg=200)),
7444
pd.Series([200], index=['My Arg'], name='a')
7445
)
7446
my_arg_metric = ('my_arg_metric', dict(title='My Arg', my_arg=300, calc_func=lambda my_arg: my_arg))
7447
pd.testing.assert_series_equal(
7448
pf.stats(my_arg_metric, column='a', settings=dict(my_arg=200)),
7449
pd.Series([300], index=['My Arg'], name='a')
7450
)
7451
pd.testing.assert_series_equal(
7452
pf.stats(my_arg_metric, column='a', settings=dict(my_arg=200),
7453
metric_settings=dict(my_arg_metric=dict(my_arg=400))),
7454
pd.Series([400], index=['My Arg'], name='a')
7455
)
7456
trade_min_pnl_cnt = (
7457
'trade_min_pnl_cnt',
7458
dict(
7459
title=vbt.Sub('Trades with PnL over $$${min_pnl}'),
7460
calc_func=lambda trades, min_pnl: trades.apply_mask(
7461
trades.pnl.values >= min_pnl).count(),
7462
resolve_trades=True
7463
)
7464
)
7465
pd.testing.assert_series_equal(
7466
pf.stats(
7467
metrics=trade_min_pnl_cnt, column='a',
7468
metric_settings=dict(trade_min_pnl_cnt=dict(min_pnl=0))),
7469
pd.Series([0], index=['Trades with PnL over $0'], name='a')
7470
)
7471
pd.testing.assert_series_equal(
7472
pf.stats(
7473
metrics=[
7474
trade_min_pnl_cnt,
7475
trade_min_pnl_cnt,
7476
trade_min_pnl_cnt
7477
],
7478
column='a',
7479
metric_settings=dict(
7480
trade_min_pnl_cnt_0=dict(min_pnl=0),
7481
trade_min_pnl_cnt_1=dict(min_pnl=10),
7482
trade_min_pnl_cnt_2=dict(min_pnl=20))
7483
),
7484
pd.Series([0, 0, 0], index=[
7485
'Trades with PnL over $0',
7486
'Trades with PnL over $10',
7487
'Trades with PnL over $20'
7488
], name='a')
7489
)
7490
pd.testing.assert_frame_equal(
7491
pf.stats(metrics='total_trades', agg_func=None, settings=dict(trades_type='entry_trades')),
7492
pd.DataFrame([2, 2, 2], index=price_na.columns, columns=['Total Trades'])
7493
)
7494
pd.testing.assert_frame_equal(
7495
pf.stats(metrics='total_trades', agg_func=None, settings=dict(trades_type='exit_trades')),
7496
pd.DataFrame([2, 2, 2], index=price_na.columns, columns=['Total Trades'])
7497
)
7498
pd.testing.assert_frame_equal(
7499
pf.stats(metrics='total_trades', agg_func=None, settings=dict(trades_type='positions')),
7500
pd.DataFrame([2, 2, 2], index=price_na.columns, columns=['Total Trades'])
7501
)
7502
pd.testing.assert_series_equal(
7503
pf['c'].stats(),
7504
pf.stats(column='c')
7505
)
7506
pd.testing.assert_series_equal(
7507
pf['c'].stats(),
7508
pf_grouped.stats(column='c', group_by=False)
7509
)
7510
pd.testing.assert_series_equal(
7511
pf_grouped['second'].stats(),
7512
pf_grouped.stats(column='second')
7513
)
7514
pd.testing.assert_series_equal(
7515
pf_grouped['second'].stats(),
7516
pf.stats(column='second', group_by=group_by)
7517
)
7518
pd.testing.assert_series_equal(
7519
pf.replace(wrapper=pf.wrapper.replace(freq='10d')).stats(),
7520
pf.stats(settings=dict(freq='10d'))
7521
)
7522
stats_df = pf.stats(agg_func=None)
7523
assert stats_df.shape == (3, 28)
7524
pd.testing.assert_index_equal(stats_df.index, pf.wrapper.columns)
7525
pd.testing.assert_index_equal(stats_df.columns, stats_index)
7526
7527
def test_returns_stats(self):
7528
pd.testing.assert_series_equal(
7529
pf.returns_stats(column='a'),
7530
pd.Series(
7531
np.array([
7532
pd.Timestamp('2020-01-01 00:00:00'), pd.Timestamp('2020-01-05 00:00:00'),
7533
pd.Timedelta('5 days 00:00:00'), -0.3104900000000077, 150.0, -20.30874297799884,
7534
1.7044081500801351, 0.3104900000000077, pd.Timedelta('4 days 00:00:00'),
7535
-13.30804491478906, -65.40868619923044, 0.0, -11.738864633265454,
7536
-1.2191070234483876, 0.12297560887596681, 0.0, 0.0, -0.0018138061822238526,
7537
-0.24888299449497553, 0.0007493142128979539
7538
]),
7539
index=pd.Index([
7540
'Start', 'End', 'Period', 'Total Return [%]', 'Benchmark Return [%]',
7541
'Annualized Return [%]', 'Annualized Volatility [%]',
7542
'Max Drawdown [%]', 'Max Drawdown Duration', 'Sharpe Ratio',
7543
'Calmar Ratio', 'Omega Ratio', 'Sortino Ratio', 'Skew', 'Kurtosis',
7544
'Tail Ratio', 'Common Sense Ratio', 'Value at Risk', 'Alpha', 'Beta'
7545
], dtype='object'),
7546
name='a')
7547
)
7548
7549
def test_plots(self):
7550
_ = pf.plot(column='a', subplots='all')
7551
_ = pf_grouped.plot(column='first', subplots='all')
7552
_ = pf_grouped.plot(column='a', subplots='all', group_by=False)
7553
_ = pf_shared.plot(column='a', subplots='all', group_by=False)
7554
with pytest.raises(Exception):
7555
_ = pf.plot(subplots='all')
7556
with pytest.raises(Exception):
7557
_ = pf_grouped.plot(subplots='all')
7558
7559