Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
polakowo
GitHub Repository: polakowo/vectorbt
Path: blob/master/tests/test_records.py
1071 views
1
from datetime import datetime
2
3
import numpy as np
4
import pandas as pd
5
import pytest
6
from numba import njit
7
8
import vectorbt as vbt
9
from tests.utils import record_arrays_close
10
from vectorbt.generic.enums import range_dt, drawdown_dt
11
from vectorbt.portfolio.enums import order_dt, trade_dt, log_dt
12
13
day_dt = np.timedelta64(86400000000000)
14
15
example_dt = np.dtype([
16
('id', np.int64),
17
('col', np.int64),
18
('idx', np.int64),
19
('some_field1', np.float64),
20
('some_field2', np.float64)
21
], align=True)
22
23
records_arr = np.asarray([
24
(0, 0, 0, 10, 21),
25
(1, 0, 1, 11, 20),
26
(2, 0, 2, 12, 19),
27
(3, 1, 0, 13, 18),
28
(4, 1, 1, 14, 17),
29
(5, 1, 2, 13, 18),
30
(6, 2, 0, 12, 19),
31
(7, 2, 1, 11, 20),
32
(8, 2, 2, 10, 21)
33
], dtype=example_dt)
34
records_nosort_arr = np.concatenate((
35
records_arr[0::3],
36
records_arr[1::3],
37
records_arr[2::3]
38
))
39
40
group_by = pd.Index(['g1', 'g1', 'g2', 'g2'])
41
42
wrapper = vbt.ArrayWrapper(
43
index=['x', 'y', 'z'],
44
columns=['a', 'b', 'c', 'd'],
45
ndim=2,
46
freq='1 days'
47
)
48
wrapper_grouped = wrapper.replace(group_by=group_by)
49
50
records = vbt.records.Records(wrapper, records_arr)
51
records_grouped = vbt.records.Records(wrapper_grouped, records_arr)
52
records_nosort = records.replace(records_arr=records_nosort_arr)
53
records_nosort_grouped = vbt.records.Records(wrapper_grouped, records_nosort_arr)
54
55
56
# ############# Global ############# #
57
58
def setup_module():
59
vbt.settings.numba['check_func_suffix'] = True
60
vbt.settings.caching.enabled = False
61
vbt.settings.caching.whitelist = []
62
vbt.settings.caching.blacklist = []
63
64
65
def teardown_module():
66
vbt.settings.reset()
67
68
69
# ############# col_mapper.py ############# #
70
71
72
class TestColumnMapper:
73
def test_col_arr(self):
74
np.testing.assert_array_equal(
75
records['a'].col_mapper.col_arr,
76
np.array([0, 0, 0])
77
)
78
np.testing.assert_array_equal(
79
records.col_mapper.col_arr,
80
np.array([0, 0, 0, 1, 1, 1, 2, 2, 2])
81
)
82
83
def test_get_col_arr(self):
84
np.testing.assert_array_equal(
85
records.col_mapper.get_col_arr(),
86
records.col_mapper.col_arr
87
)
88
np.testing.assert_array_equal(
89
records_grouped['g1'].col_mapper.get_col_arr(),
90
np.array([0, 0, 0, 0, 0, 0])
91
)
92
np.testing.assert_array_equal(
93
records_grouped.col_mapper.get_col_arr(),
94
np.array([0, 0, 0, 0, 0, 0, 1, 1, 1])
95
)
96
97
def test_col_range(self):
98
np.testing.assert_array_equal(
99
records['a'].col_mapper.col_range,
100
np.array([
101
[0, 3]
102
])
103
)
104
np.testing.assert_array_equal(
105
records.col_mapper.col_range,
106
np.array([
107
[0, 3],
108
[3, 6],
109
[6, 9],
110
[-1, -1]
111
])
112
)
113
114
def test_get_col_range(self):
115
np.testing.assert_array_equal(
116
records.col_mapper.get_col_range(),
117
np.array([
118
[0, 3],
119
[3, 6],
120
[6, 9],
121
[-1, -1]
122
])
123
)
124
np.testing.assert_array_equal(
125
records_grouped['g1'].col_mapper.get_col_range(),
126
np.array([[0, 6]])
127
)
128
np.testing.assert_array_equal(
129
records_grouped.col_mapper.get_col_range(),
130
np.array([[0, 6], [6, 9]])
131
)
132
133
def test_col_map(self):
134
np.testing.assert_array_equal(
135
records['a'].col_mapper.col_map[0],
136
np.array([0, 1, 2])
137
)
138
np.testing.assert_array_equal(
139
records['a'].col_mapper.col_map[1],
140
np.array([3])
141
)
142
np.testing.assert_array_equal(
143
records.col_mapper.col_map[0],
144
np.array([0, 1, 2, 3, 4, 5, 6, 7, 8])
145
)
146
np.testing.assert_array_equal(
147
records.col_mapper.col_map[1],
148
np.array([3, 3, 3, 0])
149
)
150
151
def test_get_col_map(self):
152
np.testing.assert_array_equal(
153
records.col_mapper.get_col_map()[0],
154
records.col_mapper.col_map[0]
155
)
156
np.testing.assert_array_equal(
157
records.col_mapper.get_col_map()[1],
158
records.col_mapper.col_map[1]
159
)
160
np.testing.assert_array_equal(
161
records_grouped['g1'].col_mapper.get_col_map()[0],
162
np.array([0, 1, 2, 3, 4, 5])
163
)
164
np.testing.assert_array_equal(
165
records_grouped['g1'].col_mapper.get_col_map()[1],
166
np.array([6])
167
)
168
np.testing.assert_array_equal(
169
records_grouped.col_mapper.get_col_map()[0],
170
np.array([0, 1, 2, 3, 4, 5, 6, 7, 8])
171
)
172
np.testing.assert_array_equal(
173
records_grouped.col_mapper.get_col_map()[1],
174
np.array([6, 3])
175
)
176
177
def test_is_sorted(self):
178
assert records.col_mapper.is_sorted()
179
assert not records_nosort.col_mapper.is_sorted()
180
181
182
# ############# mapped_array.py ############# #
183
184
mapped_array = records.map_field('some_field1')
185
mapped_array_grouped = records_grouped.map_field('some_field1')
186
mapped_array_nosort = records_nosort.map_field('some_field1')
187
mapped_array_nosort_grouped = records_nosort_grouped.map_field('some_field1')
188
mapping = {x: 'test_' + str(x) for x in pd.unique(mapped_array.values)}
189
mp_mapped_array = mapped_array.replace(mapping=mapping)
190
mp_mapped_array_grouped = mapped_array_grouped.replace(mapping=mapping)
191
192
193
class TestMappedArray:
194
def test_config(self, tmp_path):
195
assert vbt.MappedArray.loads(mapped_array.dumps()) == mapped_array
196
mapped_array.save(tmp_path / 'mapped_array')
197
assert vbt.MappedArray.load(tmp_path / 'mapped_array') == mapped_array
198
199
def test_mapped_arr(self):
200
np.testing.assert_array_equal(
201
mapped_array['a'].values,
202
np.array([10., 11., 12.])
203
)
204
np.testing.assert_array_equal(
205
mapped_array.values,
206
np.array([10., 11., 12., 13., 14., 13., 12., 11., 10.])
207
)
208
209
def test_id_arr(self):
210
np.testing.assert_array_equal(
211
mapped_array['a'].id_arr,
212
np.array([0, 1, 2])
213
)
214
np.testing.assert_array_equal(
215
mapped_array.id_arr,
216
np.array([0, 1, 2, 3, 4, 5, 6, 7, 8])
217
)
218
219
def test_col_arr(self):
220
np.testing.assert_array_equal(
221
mapped_array['a'].col_arr,
222
np.array([0, 0, 0])
223
)
224
np.testing.assert_array_equal(
225
mapped_array.col_arr,
226
np.array([0, 0, 0, 1, 1, 1, 2, 2, 2])
227
)
228
229
def test_idx_arr(self):
230
np.testing.assert_array_equal(
231
mapped_array['a'].idx_arr,
232
np.array([0, 1, 2])
233
)
234
np.testing.assert_array_equal(
235
mapped_array.idx_arr,
236
np.array([0, 1, 2, 0, 1, 2, 0, 1, 2])
237
)
238
239
def test_is_sorted(self):
240
assert mapped_array.is_sorted()
241
assert mapped_array.is_sorted(incl_id=True)
242
assert not mapped_array_nosort.is_sorted()
243
assert not mapped_array_nosort.is_sorted(incl_id=True)
244
245
def test_sort(self):
246
assert mapped_array.sort().is_sorted()
247
assert mapped_array.sort().is_sorted(incl_id=True)
248
assert mapped_array.sort(incl_id=True).is_sorted(incl_id=True)
249
assert mapped_array_nosort.sort().is_sorted()
250
assert mapped_array_nosort.sort().is_sorted(incl_id=True)
251
assert mapped_array_nosort.sort(incl_id=True).is_sorted(incl_id=True)
252
253
def test_apply_mask(self):
254
mask_a = mapped_array['a'].values >= mapped_array['a'].values.mean()
255
np.testing.assert_array_equal(
256
mapped_array['a'].apply_mask(mask_a).id_arr,
257
np.array([1, 2])
258
)
259
mask = mapped_array.values >= mapped_array.values.mean()
260
filtered = mapped_array.apply_mask(mask)
261
np.testing.assert_array_equal(
262
filtered.id_arr,
263
np.array([2, 3, 4, 5, 6])
264
)
265
np.testing.assert_array_equal(filtered.col_arr, mapped_array.col_arr[mask])
266
np.testing.assert_array_equal(filtered.idx_arr, mapped_array.idx_arr[mask])
267
assert mapped_array_grouped.apply_mask(mask).wrapper == mapped_array_grouped.wrapper
268
assert mapped_array_grouped.apply_mask(mask, group_by=False).wrapper.grouper.group_by is None
269
270
def test_map_to_mask(self):
271
@njit
272
def every_2_nb(inout, idxs, col, mapped_arr):
273
inout[idxs[::2]] = True
274
275
np.testing.assert_array_equal(
276
mapped_array.map_to_mask(every_2_nb),
277
np.array([True, False, True, True, False, True, True, False, True])
278
)
279
280
def test_top_n_mask(self):
281
np.testing.assert_array_equal(
282
mapped_array.top_n_mask(1),
283
np.array([False, False, True, False, True, False, True, False, False])
284
)
285
286
def test_bottom_n_mask(self):
287
np.testing.assert_array_equal(
288
mapped_array.bottom_n_mask(1),
289
np.array([True, False, False, True, False, False, False, False, True])
290
)
291
292
def test_top_n(self):
293
np.testing.assert_array_equal(
294
mapped_array.top_n(1).id_arr,
295
np.array([2, 4, 6])
296
)
297
298
def test_bottom_n(self):
299
np.testing.assert_array_equal(
300
mapped_array.bottom_n(1).id_arr,
301
np.array([0, 3, 8])
302
)
303
304
def test_to_pd(self):
305
target = pd.DataFrame(
306
np.array([
307
[10., 13., 12., np.nan],
308
[11., 14., 11., np.nan],
309
[12., 13., 10., np.nan]
310
]),
311
index=wrapper.index,
312
columns=wrapper.columns
313
)
314
pd.testing.assert_series_equal(
315
mapped_array['a'].to_pd(),
316
target['a']
317
)
318
pd.testing.assert_frame_equal(
319
mapped_array.to_pd(),
320
target
321
)
322
pd.testing.assert_frame_equal(
323
mapped_array.to_pd(fill_value=0.),
324
target.fillna(0.)
325
)
326
mapped_array2 = vbt.MappedArray(
327
wrapper,
328
records_arr['some_field1'].tolist() + [1],
329
records_arr['col'].tolist() + [2],
330
idx_arr=records_arr['idx'].tolist() + [2]
331
)
332
with pytest.raises(Exception):
333
_ = mapped_array2.to_pd()
334
pd.testing.assert_series_equal(
335
mapped_array['a'].to_pd(ignore_index=True),
336
pd.Series(np.array([10., 11., 12.]), name='a')
337
)
338
pd.testing.assert_frame_equal(
339
mapped_array.to_pd(ignore_index=True),
340
pd.DataFrame(
341
np.array([
342
[10., 13., 12., np.nan],
343
[11., 14., 11., np.nan],
344
[12., 13., 10., np.nan]
345
]),
346
columns=wrapper.columns
347
)
348
)
349
pd.testing.assert_frame_equal(
350
mapped_array.to_pd(fill_value=0, ignore_index=True),
351
pd.DataFrame(
352
np.array([
353
[10., 13., 12., 0.],
354
[11., 14., 11., 0.],
355
[12., 13., 10., 0.]
356
]),
357
columns=wrapper.columns
358
)
359
)
360
pd.testing.assert_frame_equal(
361
mapped_array_grouped.to_pd(ignore_index=True),
362
pd.DataFrame(
363
np.array([
364
[10., 12.],
365
[11., 11.],
366
[12., 10.],
367
[13., np.nan],
368
[14., np.nan],
369
[13., np.nan],
370
]),
371
columns=pd.Index(['g1', 'g2'], dtype='object')
372
)
373
)
374
375
def test_apply(self):
376
@njit
377
def cumsum_apply_nb(idxs, col, a):
378
return np.cumsum(a)
379
380
np.testing.assert_array_equal(
381
mapped_array['a'].apply(cumsum_apply_nb).values,
382
np.array([10., 21., 33.])
383
)
384
np.testing.assert_array_equal(
385
mapped_array.apply(cumsum_apply_nb).values,
386
np.array([10., 21., 33., 13., 27., 40., 12., 23., 33.])
387
)
388
np.testing.assert_array_equal(
389
mapped_array_grouped.apply(cumsum_apply_nb, apply_per_group=False).values,
390
np.array([10., 21., 33., 13., 27., 40., 12., 23., 33.])
391
)
392
np.testing.assert_array_equal(
393
mapped_array_grouped.apply(cumsum_apply_nb, apply_per_group=True).values,
394
np.array([10., 21., 33., 46., 60., 73., 12., 23., 33.])
395
)
396
assert mapped_array_grouped.apply(cumsum_apply_nb).wrapper == \
397
mapped_array.apply(cumsum_apply_nb, group_by=group_by).wrapper
398
assert mapped_array.apply(cumsum_apply_nb, group_by=False).wrapper.grouper.group_by is None
399
400
def test_reduce(self):
401
@njit
402
def mean_reduce_nb(col, a):
403
return np.mean(a)
404
405
assert mapped_array['a'].reduce(mean_reduce_nb) == 11.
406
pd.testing.assert_series_equal(
407
mapped_array.reduce(mean_reduce_nb),
408
pd.Series(np.array([11., 13.333333333333334, 11., np.nan]), index=wrapper.columns).rename('reduce')
409
)
410
pd.testing.assert_series_equal(
411
mapped_array.reduce(mean_reduce_nb, fill_value=0.),
412
pd.Series(np.array([11., 13.333333333333334, 11., 0.]), index=wrapper.columns).rename('reduce')
413
)
414
pd.testing.assert_series_equal(
415
mapped_array.reduce(mean_reduce_nb, wrap_kwargs=dict(to_timedelta=True)),
416
pd.Series(np.array([11., 13.333333333333334, 11., np.nan]), index=wrapper.columns).rename('reduce') * day_dt
417
)
418
pd.testing.assert_series_equal(
419
mapped_array_grouped.reduce(mean_reduce_nb),
420
pd.Series([12.166666666666666, 11.0], index=pd.Index(['g1', 'g2'], dtype='object')).rename('reduce')
421
)
422
assert mapped_array_grouped['g1'].reduce(mean_reduce_nb) == 12.166666666666666
423
pd.testing.assert_series_equal(
424
mapped_array_grouped[['g1']].reduce(mean_reduce_nb),
425
pd.Series([12.166666666666666], index=pd.Index(['g1'], dtype='object')).rename('reduce')
426
)
427
pd.testing.assert_series_equal(
428
mapped_array.reduce(mean_reduce_nb),
429
mapped_array_grouped.reduce(mean_reduce_nb, group_by=False)
430
)
431
pd.testing.assert_series_equal(
432
mapped_array.reduce(mean_reduce_nb, group_by=group_by),
433
mapped_array_grouped.reduce(mean_reduce_nb)
434
)
435
436
def test_reduce_to_idx(self):
437
@njit
438
def argmin_reduce_nb(col, a):
439
return np.argmin(a)
440
441
assert mapped_array['a'].reduce(argmin_reduce_nb, returns_idx=True) == 'x'
442
pd.testing.assert_series_equal(
443
mapped_array.reduce(argmin_reduce_nb, returns_idx=True),
444
pd.Series(np.array(['x', 'x', 'z', np.nan], dtype=object), index=wrapper.columns).rename('reduce')
445
)
446
pd.testing.assert_series_equal(
447
mapped_array.reduce(argmin_reduce_nb, returns_idx=True, to_index=False),
448
pd.Series(np.array([0, 0, 2, -1], dtype=int), index=wrapper.columns).rename('reduce')
449
)
450
pd.testing.assert_series_equal(
451
mapped_array_grouped.reduce(argmin_reduce_nb, returns_idx=True, to_index=False),
452
pd.Series(np.array([0, 2], dtype=int), index=pd.Index(['g1', 'g2'], dtype='object')).rename('reduce')
453
)
454
455
def test_reduce_to_array(self):
456
@njit
457
def min_max_reduce_nb(col, a):
458
return np.array([np.min(a), np.max(a)])
459
460
pd.testing.assert_series_equal(
461
mapped_array['a'].reduce(min_max_reduce_nb, returns_array=True,
462
wrap_kwargs=dict(name_or_index=['min', 'max'])),
463
pd.Series([10., 12.], index=pd.Index(['min', 'max'], dtype='object'), name='a')
464
)
465
pd.testing.assert_frame_equal(
466
mapped_array.reduce(min_max_reduce_nb, returns_array=True, wrap_kwargs=dict(name_or_index=['min', 'max'])),
467
pd.DataFrame(
468
np.array([
469
[10., 13., 10., np.nan],
470
[12., 14., 12., np.nan]
471
]),
472
index=pd.Index(['min', 'max'], dtype='object'),
473
columns=wrapper.columns
474
)
475
)
476
pd.testing.assert_frame_equal(
477
mapped_array.reduce(min_max_reduce_nb, returns_array=True, fill_value=0.),
478
pd.DataFrame(
479
np.array([
480
[10., 13., 10., 0.],
481
[12., 14., 12., 0.]
482
]),
483
columns=wrapper.columns
484
)
485
)
486
pd.testing.assert_frame_equal(
487
mapped_array.reduce(min_max_reduce_nb, returns_array=True, wrap_kwargs=dict(to_timedelta=True)),
488
pd.DataFrame(
489
np.array([
490
[10., 13., 10., np.nan],
491
[12., 14., 12., np.nan]
492
]),
493
columns=wrapper.columns
494
) * day_dt
495
)
496
pd.testing.assert_frame_equal(
497
mapped_array_grouped.reduce(min_max_reduce_nb, returns_array=True),
498
pd.DataFrame(
499
np.array([
500
[10., 10.],
501
[14., 12.]
502
]),
503
columns=pd.Index(['g1', 'g2'], dtype='object')
504
)
505
)
506
pd.testing.assert_frame_equal(
507
mapped_array.reduce(min_max_reduce_nb, returns_array=True),
508
mapped_array_grouped.reduce(min_max_reduce_nb, returns_array=True, group_by=False)
509
)
510
pd.testing.assert_frame_equal(
511
mapped_array.reduce(min_max_reduce_nb, returns_array=True, group_by=group_by),
512
mapped_array_grouped.reduce(min_max_reduce_nb, returns_array=True)
513
)
514
pd.testing.assert_series_equal(
515
mapped_array_grouped['g1'].reduce(min_max_reduce_nb, returns_array=True),
516
pd.Series([10., 14.], name='g1')
517
)
518
pd.testing.assert_frame_equal(
519
mapped_array_grouped[['g1']].reduce(min_max_reduce_nb, returns_array=True),
520
pd.DataFrame([[10.], [14.]], columns=pd.Index(['g1'], dtype='object'))
521
)
522
523
def test_reduce_to_idx_array(self):
524
@njit
525
def idxmin_idxmax_reduce_nb(col, a):
526
return np.array([np.argmin(a), np.argmax(a)])
527
528
pd.testing.assert_series_equal(
529
mapped_array['a'].reduce(
530
idxmin_idxmax_reduce_nb,
531
returns_array=True,
532
returns_idx=True,
533
wrap_kwargs=dict(name_or_index=['min', 'max'])
534
),
535
pd.Series(
536
np.array(['x', 'z'], dtype=object),
537
index=pd.Index(['min', 'max'], dtype='object'),
538
name='a'
539
)
540
)
541
pd.testing.assert_frame_equal(
542
mapped_array.reduce(
543
idxmin_idxmax_reduce_nb,
544
returns_array=True,
545
returns_idx=True,
546
wrap_kwargs=dict(name_or_index=['min', 'max'])
547
),
548
pd.DataFrame(
549
{
550
'a': ['x', 'z'],
551
'b': ['x', 'y'],
552
'c': ['z', 'x'],
553
'd': [np.nan, np.nan]
554
},
555
index=pd.Index(['min', 'max'], dtype='object')
556
)
557
)
558
pd.testing.assert_frame_equal(
559
mapped_array.reduce(
560
idxmin_idxmax_reduce_nb,
561
returns_array=True,
562
returns_idx=True,
563
to_index=False
564
),
565
pd.DataFrame(
566
np.array([
567
[0, 0, 2, -1],
568
[2, 1, 0, -1]
569
]),
570
columns=wrapper.columns
571
)
572
)
573
pd.testing.assert_frame_equal(
574
mapped_array_grouped.reduce(
575
idxmin_idxmax_reduce_nb,
576
returns_array=True,
577
returns_idx=True,
578
to_index=False
579
),
580
pd.DataFrame(
581
np.array([
582
[0, 2],
583
[1, 0]
584
]),
585
columns=pd.Index(['g1', 'g2'], dtype='object')
586
)
587
)
588
589
def test_nth(self):
590
assert mapped_array['a'].nth(0) == 10.
591
pd.testing.assert_series_equal(
592
mapped_array.nth(0),
593
pd.Series(np.array([10., 13., 12., np.nan]), index=wrapper.columns).rename('nth')
594
)
595
assert mapped_array['a'].nth(-1) == 12.
596
pd.testing.assert_series_equal(
597
mapped_array.nth(-1),
598
pd.Series(np.array([12., 13., 10., np.nan]), index=wrapper.columns).rename('nth')
599
)
600
with pytest.raises(Exception):
601
_ = mapped_array.nth(10)
602
pd.testing.assert_series_equal(
603
mapped_array_grouped.nth(0),
604
pd.Series(np.array([10., 12.]), index=pd.Index(['g1', 'g2'], dtype='object')).rename('nth')
605
)
606
607
def test_nth_index(self):
608
assert mapped_array['a'].nth(0) == 10.
609
pd.testing.assert_series_equal(
610
mapped_array.nth_index(0),
611
pd.Series(
612
np.array(['x', 'x', 'x', np.nan], dtype='object'),
613
index=wrapper.columns
614
).rename('nth_index')
615
)
616
assert mapped_array['a'].nth(-1) == 12.
617
pd.testing.assert_series_equal(
618
mapped_array.nth_index(-1),
619
pd.Series(
620
np.array(['z', 'z', 'z', np.nan], dtype='object'),
621
index=wrapper.columns
622
).rename('nth_index')
623
)
624
with pytest.raises(Exception):
625
_ = mapped_array.nth_index(10)
626
pd.testing.assert_series_equal(
627
mapped_array_grouped.nth_index(0),
628
pd.Series(
629
np.array(['x', 'x'], dtype='object'),
630
index=pd.Index(['g1', 'g2'], dtype='object')
631
).rename('nth_index')
632
)
633
634
def test_min(self):
635
assert mapped_array['a'].min() == mapped_array['a'].to_pd().min()
636
pd.testing.assert_series_equal(
637
mapped_array.min(),
638
mapped_array.to_pd().min().rename('min')
639
)
640
pd.testing.assert_series_equal(
641
mapped_array_grouped.min(),
642
pd.Series([10., 10.], index=pd.Index(['g1', 'g2'], dtype='object')).rename('min')
643
)
644
645
def test_max(self):
646
assert mapped_array['a'].max() == mapped_array['a'].to_pd().max()
647
pd.testing.assert_series_equal(
648
mapped_array.max(),
649
mapped_array.to_pd().max().rename('max')
650
)
651
pd.testing.assert_series_equal(
652
mapped_array_grouped.max(),
653
pd.Series([14., 12.], index=pd.Index(['g1', 'g2'], dtype='object')).rename('max')
654
)
655
656
def test_mean(self):
657
assert mapped_array['a'].mean() == mapped_array['a'].to_pd().mean()
658
pd.testing.assert_series_equal(
659
mapped_array.mean(),
660
mapped_array.to_pd().mean().rename('mean')
661
)
662
pd.testing.assert_series_equal(
663
mapped_array_grouped.mean(),
664
pd.Series([12.166667, 11.], index=pd.Index(['g1', 'g2'], dtype='object')).rename('mean')
665
)
666
667
def test_median(self):
668
assert mapped_array['a'].median() == mapped_array['a'].to_pd().median()
669
pd.testing.assert_series_equal(
670
mapped_array.median(),
671
mapped_array.to_pd().median().rename('median')
672
)
673
pd.testing.assert_series_equal(
674
mapped_array_grouped.median(),
675
pd.Series([12.5, 11.], index=pd.Index(['g1', 'g2'], dtype='object')).rename('median')
676
)
677
678
def test_std(self):
679
assert mapped_array['a'].std() == mapped_array['a'].to_pd().std()
680
pd.testing.assert_series_equal(
681
mapped_array.std(),
682
mapped_array.to_pd().std().rename('std')
683
)
684
pd.testing.assert_series_equal(
685
mapped_array.std(ddof=0),
686
mapped_array.to_pd().std(ddof=0).rename('std')
687
)
688
pd.testing.assert_series_equal(
689
mapped_array_grouped.std(),
690
pd.Series([1.4719601443879746, 1.0], index=pd.Index(['g1', 'g2'], dtype='object')).rename('std')
691
)
692
693
def test_sum(self):
694
assert mapped_array['a'].sum() == mapped_array['a'].to_pd().sum()
695
pd.testing.assert_series_equal(
696
mapped_array.sum(),
697
mapped_array.to_pd().sum().rename('sum')
698
)
699
pd.testing.assert_series_equal(
700
mapped_array_grouped.sum(),
701
pd.Series([73.0, 33.0], index=pd.Index(['g1', 'g2'], dtype='object')).rename('sum')
702
)
703
704
def test_count(self):
705
assert mapped_array['a'].count() == mapped_array['a'].to_pd().count()
706
pd.testing.assert_series_equal(
707
mapped_array.count(),
708
mapped_array.to_pd().count().rename('count')
709
)
710
pd.testing.assert_series_equal(
711
mapped_array_grouped.count(),
712
pd.Series([6, 3], index=pd.Index(['g1', 'g2'], dtype='object')).rename('count')
713
)
714
715
def test_idxmin(self):
716
assert mapped_array['a'].idxmin() == mapped_array['a'].to_pd().idxmin()
717
pd.testing.assert_series_equal(
718
mapped_array.idxmin(),
719
mapped_array.to_pd().idxmin().rename('idxmin')
720
)
721
pd.testing.assert_series_equal(
722
mapped_array_grouped.idxmin(),
723
pd.Series(
724
np.array(['x', 'z'], dtype=object),
725
index=pd.Index(['g1', 'g2'], dtype='object')
726
).rename('idxmin')
727
)
728
729
def test_idxmax(self):
730
assert mapped_array['a'].idxmax() == mapped_array['a'].to_pd().idxmax()
731
pd.testing.assert_series_equal(
732
mapped_array.idxmax(),
733
mapped_array.to_pd().idxmax().rename('idxmax')
734
)
735
pd.testing.assert_series_equal(
736
mapped_array_grouped.idxmax(),
737
pd.Series(
738
np.array(['y', 'x'], dtype=object),
739
index=pd.Index(['g1', 'g2'], dtype='object')
740
).rename('idxmax')
741
)
742
743
def test_describe(self):
744
pd.testing.assert_series_equal(
745
mapped_array['a'].describe(),
746
mapped_array['a'].to_pd().describe()
747
)
748
pd.testing.assert_frame_equal(
749
mapped_array.describe(percentiles=None),
750
mapped_array.to_pd().describe(percentiles=None)
751
)
752
pd.testing.assert_frame_equal(
753
mapped_array.describe(percentiles=[]),
754
mapped_array.to_pd().describe(percentiles=[])
755
)
756
pd.testing.assert_frame_equal(
757
mapped_array.describe(percentiles=np.arange(0, 1, 0.1)),
758
mapped_array.to_pd().describe(percentiles=np.arange(0, 1, 0.1))
759
)
760
pd.testing.assert_frame_equal(
761
mapped_array_grouped.describe(),
762
pd.DataFrame(
763
np.array([
764
[6., 3.],
765
[12.16666667, 11.],
766
[1.47196014, 1.],
767
[10., 10.],
768
[11.25, 10.5],
769
[12.5, 11.],
770
[13., 11.5],
771
[14., 12.]
772
]),
773
columns=pd.Index(['g1', 'g2'], dtype='object'),
774
index=mapped_array.describe().index
775
)
776
)
777
778
def test_value_counts(self):
779
pd.testing.assert_series_equal(
780
mapped_array['a'].value_counts(),
781
pd.Series(
782
np.array([1, 1, 1]),
783
index=pd.Index([10.0, 11.0, 12.0], dtype='float64'),
784
name='a'
785
)
786
)
787
pd.testing.assert_series_equal(
788
mapped_array['a'].value_counts(mapping=mapping),
789
pd.Series(
790
np.array([1, 1, 1]),
791
index=pd.Index(['test_10.0', 'test_11.0', 'test_12.0'], dtype='object'),
792
name='a'
793
)
794
)
795
pd.testing.assert_frame_equal(
796
mapped_array.value_counts(),
797
pd.DataFrame(
798
np.array([
799
[1, 0, 1, 0],
800
[1, 0, 1, 0],
801
[1, 0, 1, 0],
802
[0, 2, 0, 0],
803
[0, 1, 0, 0]
804
]),
805
index=pd.Index([10.0, 11.0, 12.0, 13.0, 14.0], dtype='float64'),
806
columns=wrapper.columns
807
)
808
)
809
pd.testing.assert_frame_equal(
810
mapped_array_grouped.value_counts(),
811
pd.DataFrame(
812
np.array([
813
[1, 1],
814
[1, 1],
815
[1, 1],
816
[2, 0],
817
[1, 0]
818
]),
819
index=pd.Index([10.0, 11.0, 12.0, 13.0, 14.0], dtype='float64'),
820
columns=pd.Index(['g1', 'g2'], dtype='object')
821
)
822
)
823
mapped_array2 = mapped_array.replace(mapped_arr=[4, 4, 3, 2, np.nan, 4, 3, 2, 1])
824
pd.testing.assert_frame_equal(
825
mapped_array2.value_counts(sort_uniques=False),
826
pd.DataFrame(
827
np.array([
828
[2, 1, 0, 0],
829
[1, 0, 1, 0],
830
[0, 1, 1, 0],
831
[0, 0, 1, 0],
832
[0, 1, 0, 0]
833
]),
834
index=pd.Index([4.0, 3.0, 2.0, 1.0, None], dtype='float64'),
835
columns=wrapper.columns
836
)
837
)
838
pd.testing.assert_frame_equal(
839
mapped_array2.value_counts(sort_uniques=True),
840
pd.DataFrame(
841
np.array([
842
[0, 0, 1, 0],
843
[0, 1, 1, 0],
844
[1, 0, 1, 0],
845
[2, 1, 0, 0],
846
[0, 1, 0, 0]
847
]),
848
index=pd.Index([1.0, 2.0, 3.0, 4.0, None], dtype='float64'),
849
columns=wrapper.columns
850
)
851
)
852
pd.testing.assert_frame_equal(
853
mapped_array2.value_counts(sort=True),
854
pd.DataFrame(
855
np.array([
856
[2, 1, 0, 0],
857
[0, 1, 1, 0],
858
[1, 0, 1, 0],
859
[0, 0, 1, 0],
860
[0, 1, 0, 0]
861
]),
862
index=pd.Index([4.0, 2.0, 3.0, 1.0, np.nan], dtype='float64'),
863
columns=wrapper.columns
864
)
865
)
866
pd.testing.assert_frame_equal(
867
mapped_array2.value_counts(sort=True, ascending=True),
868
pd.DataFrame(
869
np.array([
870
[0, 0, 1, 0],
871
[0, 1, 0, 0],
872
[0, 1, 1, 0],
873
[1, 0, 1, 0],
874
[2, 1, 0, 0]
875
]),
876
index=pd.Index([1.0, np.nan, 2.0, 3.0, 4.0], dtype='float64'),
877
columns=wrapper.columns
878
)
879
)
880
pd.testing.assert_frame_equal(
881
mapped_array2.value_counts(sort=True, normalize=True),
882
pd.DataFrame(
883
np.array([
884
[0.2222222222222222, 0.1111111111111111, 0.0, 0.0],
885
[0.0, 0.1111111111111111, 0.1111111111111111, 0.0],
886
[0.1111111111111111, 0.0, 0.1111111111111111, 0.0],
887
[0.0, 0.0, 0.1111111111111111, 0.0],
888
[0.0, 0.1111111111111111, 0.0, 0.0]
889
]),
890
index=pd.Index([4.0, 2.0, 3.0, 1.0, np.nan], dtype='float64'),
891
columns=wrapper.columns
892
)
893
)
894
pd.testing.assert_frame_equal(
895
mapped_array2.value_counts(sort=True, normalize=True, dropna=True),
896
pd.DataFrame(
897
np.array([
898
[0.25, 0.125, 0.0, 0.0],
899
[0.0, 0.125, 0.125, 0.0],
900
[0.125, 0.0, 0.125, 0.0],
901
[0.0, 0.0, 0.125, 0.0]
902
]),
903
index=pd.Index([4.0, 2.0, 3.0, 1.0], dtype='float64'),
904
columns=wrapper.columns
905
)
906
)
907
908
@pytest.mark.parametrize(
909
"test_nosort",
910
[False, True],
911
)
912
def test_indexing(self, test_nosort):
913
if test_nosort:
914
ma = mapped_array_nosort
915
ma_grouped = mapped_array_nosort_grouped
916
else:
917
ma = mapped_array
918
ma_grouped = mapped_array_grouped
919
np.testing.assert_array_equal(
920
ma['a'].id_arr,
921
np.array([0, 1, 2])
922
)
923
np.testing.assert_array_equal(
924
ma['a'].col_arr,
925
np.array([0, 0, 0])
926
)
927
pd.testing.assert_index_equal(
928
ma['a'].wrapper.columns,
929
pd.Index(['a'], dtype='object')
930
)
931
np.testing.assert_array_equal(
932
ma['b'].id_arr,
933
np.array([3, 4, 5])
934
)
935
np.testing.assert_array_equal(
936
ma['b'].col_arr,
937
np.array([0, 0, 0])
938
)
939
pd.testing.assert_index_equal(
940
ma['b'].wrapper.columns,
941
pd.Index(['b'], dtype='object')
942
)
943
np.testing.assert_array_equal(
944
ma[['a', 'a']].id_arr,
945
np.array([0, 1, 2, 0, 1, 2])
946
)
947
np.testing.assert_array_equal(
948
ma[['a', 'a']].col_arr,
949
np.array([0, 0, 0, 1, 1, 1])
950
)
951
pd.testing.assert_index_equal(
952
ma[['a', 'a']].wrapper.columns,
953
pd.Index(['a', 'a'], dtype='object')
954
)
955
np.testing.assert_array_equal(
956
ma[['a', 'b']].id_arr,
957
np.array([0, 1, 2, 3, 4, 5])
958
)
959
np.testing.assert_array_equal(
960
ma[['a', 'b']].col_arr,
961
np.array([0, 0, 0, 1, 1, 1])
962
)
963
pd.testing.assert_index_equal(
964
ma[['a', 'b']].wrapper.columns,
965
pd.Index(['a', 'b'], dtype='object')
966
)
967
with pytest.raises(Exception):
968
_ = ma.iloc[::2, :] # changing time not supported
969
pd.testing.assert_index_equal(
970
ma_grouped['g1'].wrapper.columns,
971
pd.Index(['a', 'b'], dtype='object')
972
)
973
assert ma_grouped['g1'].wrapper.ndim == 2
974
assert ma_grouped['g1'].wrapper.grouped_ndim == 1
975
pd.testing.assert_index_equal(
976
ma_grouped['g1'].wrapper.grouper.group_by,
977
pd.Index(['g1', 'g1'], dtype='object')
978
)
979
pd.testing.assert_index_equal(
980
ma_grouped['g2'].wrapper.columns,
981
pd.Index(['c', 'd'], dtype='object')
982
)
983
assert ma_grouped['g2'].wrapper.ndim == 2
984
assert ma_grouped['g2'].wrapper.grouped_ndim == 1
985
pd.testing.assert_index_equal(
986
ma_grouped['g2'].wrapper.grouper.group_by,
987
pd.Index(['g2', 'g2'], dtype='object')
988
)
989
pd.testing.assert_index_equal(
990
ma_grouped[['g1']].wrapper.columns,
991
pd.Index(['a', 'b'], dtype='object')
992
)
993
assert ma_grouped[['g1']].wrapper.ndim == 2
994
assert ma_grouped[['g1']].wrapper.grouped_ndim == 2
995
pd.testing.assert_index_equal(
996
ma_grouped[['g1']].wrapper.grouper.group_by,
997
pd.Index(['g1', 'g1'], dtype='object')
998
)
999
pd.testing.assert_index_equal(
1000
ma_grouped[['g1', 'g2']].wrapper.columns,
1001
pd.Index(['a', 'b', 'c', 'd'], dtype='object')
1002
)
1003
assert ma_grouped[['g1', 'g2']].wrapper.ndim == 2
1004
assert ma_grouped[['g1', 'g2']].wrapper.grouped_ndim == 2
1005
pd.testing.assert_index_equal(
1006
ma_grouped[['g1', 'g2']].wrapper.grouper.group_by,
1007
pd.Index(['g1', 'g1', 'g2', 'g2'], dtype='object')
1008
)
1009
1010
def test_magic(self):
1011
a = vbt.MappedArray(
1012
wrapper,
1013
records_arr['some_field1'],
1014
records_arr['col'],
1015
id_arr=records_arr['id'],
1016
idx_arr=records_arr['idx']
1017
)
1018
a_inv = vbt.MappedArray(
1019
wrapper,
1020
records_arr['some_field1'][::-1],
1021
records_arr['col'][::-1],
1022
id_arr=records_arr['id'][::-1],
1023
idx_arr=records_arr['idx'][::-1]
1024
)
1025
b = records_arr['some_field2']
1026
a_bool = vbt.MappedArray(
1027
wrapper,
1028
records_arr['some_field1'] > np.mean(records_arr['some_field1']),
1029
records_arr['col'],
1030
id_arr=records_arr['id'],
1031
idx_arr=records_arr['idx']
1032
)
1033
b_bool = records_arr['some_field2'] > np.mean(records_arr['some_field2'])
1034
assert a ** a == a ** 2
1035
with pytest.raises(Exception):
1036
_ = a * a_inv
1037
1038
# binary ops
1039
# comparison ops
1040
np.testing.assert_array_equal((a == b).values, a.values == b)
1041
np.testing.assert_array_equal((a != b).values, a.values != b)
1042
np.testing.assert_array_equal((a < b).values, a.values < b)
1043
np.testing.assert_array_equal((a > b).values, a.values > b)
1044
np.testing.assert_array_equal((a <= b).values, a.values <= b)
1045
np.testing.assert_array_equal((a >= b).values, a.values >= b)
1046
# arithmetic ops
1047
np.testing.assert_array_equal((a + b).values, a.values + b)
1048
np.testing.assert_array_equal((a - b).values, a.values - b)
1049
np.testing.assert_array_equal((a * b).values, a.values * b)
1050
np.testing.assert_array_equal((a ** b).values, a.values ** b)
1051
np.testing.assert_array_equal((a % b).values, a.values % b)
1052
np.testing.assert_array_equal((a // b).values, a.values // b)
1053
np.testing.assert_array_equal((a / b).values, a.values / b)
1054
# __r*__ is only called if the left object does not have an __*__ method
1055
np.testing.assert_array_equal((10 + a).values, 10 + a.values)
1056
np.testing.assert_array_equal((10 - a).values, 10 - a.values)
1057
np.testing.assert_array_equal((10 * a).values, 10 * a.values)
1058
np.testing.assert_array_equal((10 ** a).values, 10 ** a.values)
1059
np.testing.assert_array_equal((10 % a).values, 10 % a.values)
1060
np.testing.assert_array_equal((10 // a).values, 10 // a.values)
1061
np.testing.assert_array_equal((10 / a).values, 10 / a.values)
1062
# mask ops
1063
np.testing.assert_array_equal((a_bool & b_bool).values, a_bool.values & b_bool)
1064
np.testing.assert_array_equal((a_bool | b_bool).values, a_bool.values | b_bool)
1065
np.testing.assert_array_equal((a_bool ^ b_bool).values, a_bool.values ^ b_bool)
1066
np.testing.assert_array_equal((True & a_bool).values, True & a_bool.values)
1067
np.testing.assert_array_equal((True | a_bool).values, True | a_bool.values)
1068
np.testing.assert_array_equal((True ^ a_bool).values, True ^ a_bool.values)
1069
# unary ops
1070
np.testing.assert_array_equal((-a).values, -a.values)
1071
np.testing.assert_array_equal((+a).values, +a.values)
1072
np.testing.assert_array_equal((abs(-a)).values, abs((-a.values)))
1073
1074
def test_stats(self):
1075
stats_index = pd.Index([
1076
'Start', 'End', 'Period', 'Count', 'Mean', 'Std', 'Min', 'Median', 'Max', 'Min Index', 'Max Index'
1077
], dtype='object')
1078
pd.testing.assert_series_equal(
1079
mapped_array.stats(),
1080
pd.Series([
1081
'x', 'z', pd.Timedelta('3 days 00:00:00'),
1082
2.25, 11.777777777777779, 0.859116756396542, 11.0, 11.666666666666666, 12.666666666666666
1083
],
1084
index=stats_index[:-2],
1085
name='agg_func_mean'
1086
)
1087
)
1088
pd.testing.assert_series_equal(
1089
mapped_array.stats(column='a'),
1090
pd.Series([
1091
'x', 'z', pd.Timedelta('3 days 00:00:00'),
1092
3, 11.0, 1.0, 10.0, 11.0, 12.0, 'x', 'z'
1093
],
1094
index=stats_index,
1095
name='a'
1096
)
1097
)
1098
pd.testing.assert_series_equal(
1099
mapped_array.stats(column='g1', group_by=group_by),
1100
pd.Series([
1101
'x', 'z', pd.Timedelta('3 days 00:00:00'),
1102
6, 12.166666666666666, 1.4719601443879746, 10.0, 12.5, 14.0, 'x', 'y'
1103
],
1104
index=stats_index,
1105
name='g1'
1106
)
1107
)
1108
pd.testing.assert_series_equal(
1109
mapped_array['c'].stats(),
1110
mapped_array.stats(column='c')
1111
)
1112
pd.testing.assert_series_equal(
1113
mapped_array['c'].stats(),
1114
mapped_array.stats(column='c', group_by=False)
1115
)
1116
pd.testing.assert_series_equal(
1117
mapped_array_grouped['g2'].stats(),
1118
mapped_array_grouped.stats(column='g2')
1119
)
1120
pd.testing.assert_series_equal(
1121
mapped_array_grouped['g2'].stats(),
1122
mapped_array.stats(column='g2', group_by=group_by)
1123
)
1124
stats_df = mapped_array.stats(agg_func=None)
1125
assert stats_df.shape == (4, 11)
1126
pd.testing.assert_index_equal(stats_df.index, mapped_array.wrapper.columns)
1127
pd.testing.assert_index_equal(stats_df.columns, stats_index)
1128
1129
def test_stats_mapping(self):
1130
stats_index = pd.Index([
1131
'Start', 'End', 'Period', 'Count', 'Value Counts: test_10.0',
1132
'Value Counts: test_11.0', 'Value Counts: test_12.0',
1133
'Value Counts: test_13.0', 'Value Counts: test_14.0'
1134
], dtype='object')
1135
pd.testing.assert_series_equal(
1136
mp_mapped_array.stats(),
1137
pd.Series([
1138
'x',
1139
'z',
1140
pd.Timedelta('3 days 00:00:00'),
1141
2.25, 0.5, 0.5, 0.5, 0.5, 0.25
1142
],
1143
index=stats_index,
1144
name='agg_func_mean'
1145
)
1146
)
1147
pd.testing.assert_series_equal(
1148
mp_mapped_array.stats(column='a'),
1149
pd.Series([
1150
'x',
1151
'z',
1152
pd.Timedelta('3 days 00:00:00'),
1153
3, 1, 1, 1, 0, 0
1154
],
1155
index=stats_index,
1156
name='a'
1157
)
1158
)
1159
pd.testing.assert_series_equal(
1160
mp_mapped_array.stats(column='g1', group_by=group_by),
1161
pd.Series([
1162
'x',
1163
'z',
1164
pd.Timedelta('3 days 00:00:00'),
1165
6, 1, 1, 1, 2, 1
1166
],
1167
index=stats_index,
1168
name='g1'
1169
)
1170
)
1171
pd.testing.assert_series_equal(
1172
mp_mapped_array.stats(),
1173
mapped_array.stats(settings=dict(mapping=mapping))
1174
)
1175
pd.testing.assert_series_equal(
1176
mp_mapped_array['c'].stats(settings=dict(incl_all_keys=True)),
1177
mp_mapped_array.stats(column='c')
1178
)
1179
pd.testing.assert_series_equal(
1180
mp_mapped_array['c'].stats(settings=dict(incl_all_keys=True)),
1181
mp_mapped_array.stats(column='c', group_by=False)
1182
)
1183
pd.testing.assert_series_equal(
1184
mp_mapped_array_grouped['g2'].stats(settings=dict(incl_all_keys=True)),
1185
mp_mapped_array_grouped.stats(column='g2')
1186
)
1187
pd.testing.assert_series_equal(
1188
mp_mapped_array_grouped['g2'].stats(settings=dict(incl_all_keys=True)),
1189
mp_mapped_array.stats(column='g2', group_by=group_by)
1190
)
1191
stats_df = mp_mapped_array.stats(agg_func=None)
1192
assert stats_df.shape == (4, 9)
1193
pd.testing.assert_index_equal(stats_df.index, mp_mapped_array.wrapper.columns)
1194
pd.testing.assert_index_equal(stats_df.columns, stats_index)
1195
1196
1197
# ############# base.py ############# #
1198
1199
class TestRecords:
1200
def test_config(self, tmp_path):
1201
assert vbt.Records.loads(records['a'].dumps()) == records['a']
1202
assert vbt.Records.loads(records.dumps()) == records
1203
records.save(tmp_path / 'records')
1204
assert vbt.Records.load(tmp_path / 'records') == records
1205
1206
def test_records(self):
1207
pd.testing.assert_frame_equal(
1208
records.records,
1209
pd.DataFrame.from_records(records_arr)
1210
)
1211
1212
def test_recarray(self):
1213
np.testing.assert_array_equal(records['a'].recarray.some_field1, records['a'].values['some_field1'])
1214
np.testing.assert_array_equal(records.recarray.some_field1, records.values['some_field1'])
1215
1216
def test_records_readable(self):
1217
pd.testing.assert_frame_equal(
1218
records.records_readable,
1219
pd.DataFrame([
1220
[0, 'a', 'x', 10.0, 21.0], [1, 'a', 'y', 11.0, 20.0], [2, 'a', 'z', 12.0, 19.0],
1221
[3, 'b', 'x', 13.0, 18.0], [4, 'b', 'y', 14.0, 17.0], [5, 'b', 'z', 13.0, 18.0],
1222
[6, 'c', 'x', 12.0, 19.0], [7, 'c', 'y', 11.0, 20.0], [8, 'c', 'z', 10.0, 21.0]
1223
], columns=pd.Index(['Id', 'Column', 'Timestamp', 'some_field1', 'some_field2'], dtype='object'))
1224
)
1225
1226
def test_is_sorted(self):
1227
assert records.is_sorted()
1228
assert records.is_sorted(incl_id=True)
1229
assert not records_nosort.is_sorted()
1230
assert not records_nosort.is_sorted(incl_id=True)
1231
1232
def test_sort(self):
1233
assert records.sort().is_sorted()
1234
assert records.sort().is_sorted(incl_id=True)
1235
assert records.sort(incl_id=True).is_sorted(incl_id=True)
1236
assert records_nosort.sort().is_sorted()
1237
assert records_nosort.sort().is_sorted(incl_id=True)
1238
assert records_nosort.sort(incl_id=True).is_sorted(incl_id=True)
1239
1240
def test_apply_mask(self):
1241
mask_a = records['a'].values['some_field1'] >= records['a'].values['some_field1'].mean()
1242
record_arrays_close(
1243
records['a'].apply_mask(mask_a).values,
1244
np.array([
1245
(1, 0, 1, 11., 20.), (2, 0, 2, 12., 19.)
1246
], dtype=example_dt)
1247
)
1248
mask = records.values['some_field1'] >= records.values['some_field1'].mean()
1249
filtered = records.apply_mask(mask)
1250
record_arrays_close(
1251
filtered.values,
1252
np.array([
1253
(2, 0, 2, 12., 19.), (3, 1, 0, 13., 18.), (4, 1, 1, 14., 17.),
1254
(5, 1, 2, 13., 18.), (6, 2, 0, 12., 19.)
1255
], dtype=example_dt)
1256
)
1257
assert records_grouped.apply_mask(mask).wrapper == records_grouped.wrapper
1258
1259
def test_map_field(self):
1260
np.testing.assert_array_equal(
1261
records['a'].map_field('some_field1').values,
1262
np.array([10., 11., 12.])
1263
)
1264
np.testing.assert_array_equal(
1265
records.map_field('some_field1').values,
1266
np.array([10., 11., 12., 13., 14., 13., 12., 11., 10.])
1267
)
1268
assert records_grouped.map_field('some_field1').wrapper == \
1269
records.map_field('some_field1', group_by=group_by).wrapper
1270
assert records_grouped.map_field('some_field1', group_by=False).wrapper.grouper.group_by is None
1271
1272
def test_map(self):
1273
@njit
1274
def map_func_nb(record):
1275
return record['some_field1'] + record['some_field2']
1276
1277
np.testing.assert_array_equal(
1278
records['a'].map(map_func_nb).values,
1279
np.array([31., 31., 31.])
1280
)
1281
np.testing.assert_array_equal(
1282
records.map(map_func_nb).values,
1283
np.array([31., 31., 31., 31., 31., 31., 31., 31., 31.])
1284
)
1285
assert records_grouped.map(map_func_nb).wrapper == \
1286
records.map(map_func_nb, group_by=group_by).wrapper
1287
assert records_grouped.map(map_func_nb, group_by=False).wrapper.grouper.group_by is None
1288
1289
def test_map_array(self):
1290
arr = records_arr['some_field1'] + records_arr['some_field2']
1291
np.testing.assert_array_equal(
1292
records['a'].map_array(arr[:3]).values,
1293
np.array([31., 31., 31.])
1294
)
1295
np.testing.assert_array_equal(
1296
records.map_array(arr).values,
1297
np.array([31., 31., 31., 31., 31., 31., 31., 31., 31.])
1298
)
1299
assert records_grouped.map_array(arr).wrapper == \
1300
records.map_array(arr, group_by=group_by).wrapper
1301
assert records_grouped.map_array(arr, group_by=False).wrapper.grouper.group_by is None
1302
1303
def test_apply(self):
1304
@njit
1305
def cumsum_apply_nb(records):
1306
return np.cumsum(records['some_field1'])
1307
1308
np.testing.assert_array_equal(
1309
records['a'].apply(cumsum_apply_nb).values,
1310
np.array([10., 21., 33.])
1311
)
1312
np.testing.assert_array_equal(
1313
records.apply(cumsum_apply_nb).values,
1314
np.array([10., 21., 33., 13., 27., 40., 12., 23., 33.])
1315
)
1316
np.testing.assert_array_equal(
1317
records_grouped.apply(cumsum_apply_nb, apply_per_group=False).values,
1318
np.array([10., 21., 33., 13., 27., 40., 12., 23., 33.])
1319
)
1320
np.testing.assert_array_equal(
1321
records_grouped.apply(cumsum_apply_nb, apply_per_group=True).values,
1322
np.array([10., 21., 33., 46., 60., 73., 12., 23., 33.])
1323
)
1324
assert records_grouped.apply(cumsum_apply_nb).wrapper == \
1325
records.apply(cumsum_apply_nb, group_by=group_by).wrapper
1326
assert records_grouped.apply(cumsum_apply_nb, group_by=False).wrapper.grouper.group_by is None
1327
1328
def test_count(self):
1329
assert records['a'].count() == 3
1330
pd.testing.assert_series_equal(
1331
records.count(),
1332
pd.Series(
1333
np.array([3, 3, 3, 0]),
1334
index=wrapper.columns
1335
).rename('count')
1336
)
1337
assert records_grouped['g1'].count() == 6
1338
pd.testing.assert_series_equal(
1339
records_grouped.count(),
1340
pd.Series(
1341
np.array([6, 3]),
1342
index=pd.Index(['g1', 'g2'], dtype='object')
1343
).rename('count')
1344
)
1345
1346
@pytest.mark.parametrize(
1347
"test_nosort",
1348
[False, True],
1349
)
1350
def test_indexing(self, test_nosort):
1351
if test_nosort:
1352
r = records_nosort
1353
r_grouped = records_nosort_grouped
1354
else:
1355
r = records
1356
r_grouped = records_grouped
1357
record_arrays_close(
1358
r['a'].values,
1359
np.array([
1360
(0, 0, 0, 10., 21.), (1, 0, 1, 11., 20.), (2, 0, 2, 12., 19.)
1361
], dtype=example_dt)
1362
)
1363
pd.testing.assert_index_equal(
1364
r['a'].wrapper.columns,
1365
pd.Index(['a'], dtype='object')
1366
)
1367
pd.testing.assert_index_equal(
1368
r['b'].wrapper.columns,
1369
pd.Index(['b'], dtype='object')
1370
)
1371
record_arrays_close(
1372
r[['a', 'a']].values,
1373
np.array([
1374
(0, 0, 0, 10., 21.), (1, 0, 1, 11., 20.), (2, 0, 2, 12., 19.),
1375
(0, 1, 0, 10., 21.), (1, 1, 1, 11., 20.), (2, 1, 2, 12., 19.)
1376
], dtype=example_dt)
1377
)
1378
pd.testing.assert_index_equal(
1379
r[['a', 'a']].wrapper.columns,
1380
pd.Index(['a', 'a'], dtype='object')
1381
)
1382
record_arrays_close(
1383
r[['a', 'b']].values,
1384
np.array([
1385
(0, 0, 0, 10., 21.), (1, 0, 1, 11., 20.), (2, 0, 2, 12., 19.),
1386
(3, 1, 0, 13., 18.), (4, 1, 1, 14., 17.), (5, 1, 2, 13., 18.)
1387
], dtype=example_dt)
1388
)
1389
pd.testing.assert_index_equal(
1390
r[['a', 'b']].wrapper.columns,
1391
pd.Index(['a', 'b'], dtype='object')
1392
)
1393
with pytest.raises(Exception):
1394
_ = r.iloc[::2, :] # changing time not supported
1395
pd.testing.assert_index_equal(
1396
r_grouped['g1'].wrapper.columns,
1397
pd.Index(['a', 'b'], dtype='object')
1398
)
1399
assert r_grouped['g1'].wrapper.ndim == 2
1400
assert r_grouped['g1'].wrapper.grouped_ndim == 1
1401
pd.testing.assert_index_equal(
1402
r_grouped['g1'].wrapper.grouper.group_by,
1403
pd.Index(['g1', 'g1'], dtype='object')
1404
)
1405
pd.testing.assert_index_equal(
1406
r_grouped['g2'].wrapper.columns,
1407
pd.Index(['c', 'd'], dtype='object')
1408
)
1409
assert r_grouped['g2'].wrapper.ndim == 2
1410
assert r_grouped['g2'].wrapper.grouped_ndim == 1
1411
pd.testing.assert_index_equal(
1412
r_grouped['g2'].wrapper.grouper.group_by,
1413
pd.Index(['g2', 'g2'], dtype='object')
1414
)
1415
pd.testing.assert_index_equal(
1416
r_grouped[['g1']].wrapper.columns,
1417
pd.Index(['a', 'b'], dtype='object')
1418
)
1419
assert r_grouped[['g1']].wrapper.ndim == 2
1420
assert r_grouped[['g1']].wrapper.grouped_ndim == 2
1421
pd.testing.assert_index_equal(
1422
r_grouped[['g1']].wrapper.grouper.group_by,
1423
pd.Index(['g1', 'g1'], dtype='object')
1424
)
1425
pd.testing.assert_index_equal(
1426
r_grouped[['g1', 'g2']].wrapper.columns,
1427
pd.Index(['a', 'b', 'c', 'd'], dtype='object')
1428
)
1429
assert r_grouped[['g1', 'g2']].wrapper.ndim == 2
1430
assert r_grouped[['g1', 'g2']].wrapper.grouped_ndim == 2
1431
pd.testing.assert_index_equal(
1432
r_grouped[['g1', 'g2']].wrapper.grouper.group_by,
1433
pd.Index(['g1', 'g1', 'g2', 'g2'], dtype='object')
1434
)
1435
1436
def test_filtering(self):
1437
filtered_records = vbt.Records(wrapper, records_arr[[0, -1]])
1438
record_arrays_close(
1439
filtered_records.values,
1440
np.array([(0, 0, 0, 10., 21.), (8, 2, 2, 10., 21.)], dtype=example_dt)
1441
)
1442
# a
1443
record_arrays_close(
1444
filtered_records['a'].values,
1445
np.array([(0, 0, 0, 10., 21.)], dtype=example_dt)
1446
)
1447
np.testing.assert_array_equal(
1448
filtered_records['a'].map_field('some_field1').id_arr,
1449
np.array([0])
1450
)
1451
assert filtered_records['a'].map_field('some_field1').min() == 10.
1452
assert filtered_records['a'].count() == 1.
1453
# b
1454
record_arrays_close(
1455
filtered_records['b'].values,
1456
np.array([], dtype=example_dt)
1457
)
1458
np.testing.assert_array_equal(
1459
filtered_records['b'].map_field('some_field1').id_arr,
1460
np.array([])
1461
)
1462
assert np.isnan(filtered_records['b'].map_field('some_field1').min())
1463
assert filtered_records['b'].count() == 0.
1464
# c
1465
record_arrays_close(
1466
filtered_records['c'].values,
1467
np.array([(8, 0, 2, 10., 21.)], dtype=example_dt)
1468
)
1469
np.testing.assert_array_equal(
1470
filtered_records['c'].map_field('some_field1').id_arr,
1471
np.array([8])
1472
)
1473
assert filtered_records['c'].map_field('some_field1').min() == 10.
1474
assert filtered_records['c'].count() == 1.
1475
# d
1476
record_arrays_close(
1477
filtered_records['d'].values,
1478
np.array([], dtype=example_dt)
1479
)
1480
np.testing.assert_array_equal(
1481
filtered_records['d'].map_field('some_field1').id_arr,
1482
np.array([])
1483
)
1484
assert np.isnan(filtered_records['d'].map_field('some_field1').min())
1485
assert filtered_records['d'].count() == 0.
1486
1487
def test_stats(self):
1488
stats_index = pd.Index([
1489
'Start', 'End', 'Period', 'Count'
1490
], dtype='object')
1491
pd.testing.assert_series_equal(
1492
records.stats(),
1493
pd.Series([
1494
'x', 'z', pd.Timedelta('3 days 00:00:00'), 2.25
1495
],
1496
index=stats_index,
1497
name='agg_func_mean'
1498
)
1499
)
1500
pd.testing.assert_series_equal(
1501
records.stats(column='a'),
1502
pd.Series([
1503
'x', 'z', pd.Timedelta('3 days 00:00:00'), 3
1504
],
1505
index=stats_index,
1506
name='a'
1507
)
1508
)
1509
pd.testing.assert_series_equal(
1510
records.stats(column='g1', group_by=group_by),
1511
pd.Series([
1512
'x', 'z', pd.Timedelta('3 days 00:00:00'), 6
1513
],
1514
index=stats_index,
1515
name='g1'
1516
)
1517
)
1518
pd.testing.assert_series_equal(
1519
records['c'].stats(),
1520
records.stats(column='c')
1521
)
1522
pd.testing.assert_series_equal(
1523
records['c'].stats(),
1524
records.stats(column='c', group_by=False)
1525
)
1526
pd.testing.assert_series_equal(
1527
records_grouped['g2'].stats(),
1528
records_grouped.stats(column='g2')
1529
)
1530
pd.testing.assert_series_equal(
1531
records_grouped['g2'].stats(),
1532
records.stats(column='g2', group_by=group_by)
1533
)
1534
stats_df = records.stats(agg_func=None)
1535
assert stats_df.shape == (4, 4)
1536
pd.testing.assert_index_equal(stats_df.index, records.wrapper.columns)
1537
pd.testing.assert_index_equal(stats_df.columns, stats_index)
1538
1539
1540
# ############# ranges.py ############# #
1541
1542
ts = pd.DataFrame({
1543
'a': [1, -1, 3, -1, 5, -1],
1544
'b': [-1, -1, -1, 4, 5, 6],
1545
'c': [1, 2, 3, -1, -1, -1],
1546
'd': [-1, -1, -1, -1, -1, -1]
1547
}, index=[
1548
datetime(2020, 1, 1),
1549
datetime(2020, 1, 2),
1550
datetime(2020, 1, 3),
1551
datetime(2020, 1, 4),
1552
datetime(2020, 1, 5),
1553
datetime(2020, 1, 6)
1554
])
1555
1556
ranges = vbt.Ranges.from_ts(ts, wrapper_kwargs=dict(freq='1 days'))
1557
ranges_grouped = vbt.Ranges.from_ts(ts, wrapper_kwargs=dict(freq='1 days', group_by=group_by))
1558
1559
1560
class TestRanges:
1561
def test_mapped_fields(self):
1562
for name in range_dt.names:
1563
np.testing.assert_array_equal(
1564
getattr(ranges, name).values,
1565
ranges.values[name]
1566
)
1567
1568
def test_from_ts(self):
1569
record_arrays_close(
1570
ranges.values,
1571
np.array([
1572
(0, 0, 0, 1, 1), (1, 0, 2, 3, 1), (2, 0, 4, 5, 1), (3, 1, 3, 5, 0), (4, 2, 0, 3, 1)
1573
], dtype=range_dt)
1574
)
1575
assert ranges.wrapper.freq == day_dt
1576
pd.testing.assert_index_equal(
1577
ranges_grouped.wrapper.grouper.group_by,
1578
group_by
1579
)
1580
1581
def test_records_readable(self):
1582
records_readable = ranges.records_readable
1583
1584
np.testing.assert_array_equal(
1585
records_readable['Range Id'].values,
1586
np.array([
1587
0, 1, 2, 3, 4
1588
])
1589
)
1590
np.testing.assert_array_equal(
1591
records_readable['Column'].values,
1592
np.array([
1593
'a', 'a', 'a', 'b', 'c'
1594
])
1595
)
1596
np.testing.assert_array_equal(
1597
records_readable['Start Timestamp'].values,
1598
np.array([
1599
'2020-01-01T00:00:00.000000000', '2020-01-03T00:00:00.000000000',
1600
'2020-01-05T00:00:00.000000000', '2020-01-04T00:00:00.000000000',
1601
'2020-01-01T00:00:00.000000000'
1602
], dtype='datetime64[ns]')
1603
)
1604
np.testing.assert_array_equal(
1605
records_readable['End Timestamp'].values,
1606
np.array([
1607
'2020-01-02T00:00:00.000000000', '2020-01-04T00:00:00.000000000',
1608
'2020-01-06T00:00:00.000000000', '2020-01-06T00:00:00.000000000',
1609
'2020-01-04T00:00:00.000000000'
1610
], dtype='datetime64[ns]')
1611
)
1612
np.testing.assert_array_equal(
1613
records_readable['Status'].values,
1614
np.array([
1615
'Closed', 'Closed', 'Closed', 'Open', 'Closed'
1616
])
1617
)
1618
1619
def test_to_mask(self):
1620
pd.testing.assert_series_equal(
1621
ranges['a'].to_mask(),
1622
ts['a'] != -1
1623
)
1624
pd.testing.assert_frame_equal(
1625
ranges.to_mask(),
1626
ts != -1
1627
)
1628
pd.testing.assert_frame_equal(
1629
ranges_grouped.to_mask(),
1630
pd.DataFrame(
1631
[
1632
[True, True],
1633
[False, True],
1634
[True, True],
1635
[True, False],
1636
[True, False],
1637
[True, False]
1638
],
1639
index=ts.index,
1640
columns=pd.Index(['g1', 'g2'], dtype='object')
1641
)
1642
)
1643
1644
def test_duration(self):
1645
np.testing.assert_array_equal(
1646
ranges['a'].duration.values,
1647
np.array([1, 1, 1])
1648
)
1649
np.testing.assert_array_equal(
1650
ranges.duration.values,
1651
np.array([1, 1, 1, 3, 3])
1652
)
1653
1654
def test_avg_duration(self):
1655
assert ranges['a'].avg_duration() == pd.Timedelta('1 days 00:00:00')
1656
pd.testing.assert_series_equal(
1657
ranges.avg_duration(),
1658
pd.Series(
1659
np.array([86400000000000, 259200000000000, 259200000000000, 'NaT'], dtype='timedelta64[ns]'),
1660
index=wrapper.columns
1661
).rename('avg_duration')
1662
)
1663
pd.testing.assert_series_equal(
1664
ranges_grouped.avg_duration(),
1665
pd.Series(
1666
np.array([129600000000000, 259200000000000], dtype='timedelta64[ns]'),
1667
index=pd.Index(['g1', 'g2'], dtype='object')
1668
).rename('avg_duration')
1669
)
1670
1671
def test_max_duration(self):
1672
assert ranges['a'].max_duration() == pd.Timedelta('1 days 00:00:00')
1673
pd.testing.assert_series_equal(
1674
ranges.max_duration(),
1675
pd.Series(
1676
np.array([86400000000000, 259200000000000, 259200000000000, 'NaT'], dtype='timedelta64[ns]'),
1677
index=wrapper.columns
1678
).rename('max_duration')
1679
)
1680
pd.testing.assert_series_equal(
1681
ranges_grouped.max_duration(),
1682
pd.Series(
1683
np.array([259200000000000, 259200000000000], dtype='timedelta64[ns]'),
1684
index=pd.Index(['g1', 'g2'], dtype='object')
1685
).rename('max_duration')
1686
)
1687
1688
def test_coverage(self):
1689
assert ranges['a'].coverage() == 0.5
1690
pd.testing.assert_series_equal(
1691
ranges.coverage(),
1692
pd.Series(
1693
np.array([0.5, 0.5, 0.5, np.nan]),
1694
index=ts2.columns
1695
).rename('coverage')
1696
)
1697
pd.testing.assert_series_equal(
1698
ranges.coverage(),
1699
ranges.replace(records_arr=np.repeat(ranges.values, 2)).coverage()
1700
)
1701
pd.testing.assert_series_equal(
1702
ranges.replace(records_arr=np.repeat(ranges.values, 2)).coverage(overlapping=True),
1703
pd.Series(
1704
np.array([1.0, 1.0, 1.0, np.nan]),
1705
index=ts2.columns
1706
).rename('coverage')
1707
)
1708
pd.testing.assert_series_equal(
1709
ranges.coverage(normalize=False),
1710
pd.Series(
1711
np.array([3.0, 3.0, 3.0, np.nan]),
1712
index=ts2.columns
1713
).rename('coverage')
1714
)
1715
pd.testing.assert_series_equal(
1716
ranges.replace(records_arr=np.repeat(ranges.values, 2)).coverage(overlapping=True, normalize=False),
1717
pd.Series(
1718
np.array([3.0, 3.0, 3.0, np.nan]),
1719
index=ts2.columns
1720
).rename('coverage')
1721
)
1722
pd.testing.assert_series_equal(
1723
ranges_grouped.coverage(),
1724
pd.Series(
1725
np.array([0.4166666666666667, 0.25]),
1726
index=pd.Index(['g1', 'g2'], dtype='object')
1727
).rename('coverage')
1728
)
1729
pd.testing.assert_series_equal(
1730
ranges_grouped.coverage(),
1731
ranges_grouped.replace(records_arr=np.repeat(ranges_grouped.values, 2)).coverage()
1732
)
1733
1734
def test_stats(self):
1735
stats_index = pd.Index([
1736
'Start', 'End', 'Period', 'Coverage', 'Overlap Coverage',
1737
'Total Records', 'Duration: Min', 'Duration: Median', 'Duration: Max',
1738
'Duration: Mean', 'Duration: Std'
1739
], dtype='object')
1740
pd.testing.assert_series_equal(
1741
ranges.stats(),
1742
pd.Series([
1743
pd.Timestamp('2020-01-01 00:00:00'), pd.Timestamp('2020-01-06 00:00:00'),
1744
pd.Timedelta('6 days 00:00:00'), pd.Timedelta('3 days 00:00:00'),
1745
pd.Timedelta('0 days 00:00:00'), 1.25, pd.Timedelta('2 days 08:00:00'),
1746
pd.Timedelta('2 days 08:00:00'), pd.Timedelta('2 days 08:00:00'),
1747
pd.Timedelta('2 days 08:00:00'), pd.Timedelta('0 days 00:00:00')
1748
],
1749
index=stats_index,
1750
name='agg_func_mean'
1751
)
1752
)
1753
pd.testing.assert_series_equal(
1754
ranges.stats(column='a'),
1755
pd.Series([
1756
pd.Timestamp('2020-01-01 00:00:00'), pd.Timestamp('2020-01-06 00:00:00'),
1757
pd.Timedelta('6 days 00:00:00'), pd.Timedelta('3 days 00:00:00'),
1758
pd.Timedelta('0 days 00:00:00'), 3, pd.Timedelta('1 days 00:00:00'),
1759
pd.Timedelta('1 days 00:00:00'), pd.Timedelta('1 days 00:00:00'),
1760
pd.Timedelta('1 days 00:00:00'), pd.Timedelta('0 days 00:00:00')
1761
],
1762
index=stats_index,
1763
name='a'
1764
)
1765
)
1766
pd.testing.assert_series_equal(
1767
ranges.stats(column='g1', group_by=group_by),
1768
pd.Series([
1769
pd.Timestamp('2020-01-01 00:00:00'), pd.Timestamp('2020-01-06 00:00:00'),
1770
pd.Timedelta('6 days 00:00:00'), pd.Timedelta('5 days 00:00:00'),
1771
pd.Timedelta('1 days 00:00:00'), 4, pd.Timedelta('1 days 00:00:00'),
1772
pd.Timedelta('1 days 00:00:00'), pd.Timedelta('3 days 00:00:00'),
1773
pd.Timedelta('1 days 12:00:00'), pd.Timedelta('1 days 00:00:00')
1774
],
1775
index=stats_index,
1776
name='g1'
1777
)
1778
)
1779
pd.testing.assert_series_equal(
1780
ranges['c'].stats(),
1781
ranges.stats(column='c')
1782
)
1783
pd.testing.assert_series_equal(
1784
ranges['c'].stats(),
1785
ranges.stats(column='c', group_by=False)
1786
)
1787
pd.testing.assert_series_equal(
1788
ranges_grouped['g2'].stats(),
1789
ranges_grouped.stats(column='g2')
1790
)
1791
pd.testing.assert_series_equal(
1792
ranges_grouped['g2'].stats(),
1793
ranges.stats(column='g2', group_by=group_by)
1794
)
1795
stats_df = ranges.stats(agg_func=None)
1796
assert stats_df.shape == (4, 11)
1797
pd.testing.assert_index_equal(stats_df.index, ranges.wrapper.columns)
1798
pd.testing.assert_index_equal(stats_df.columns, stats_index)
1799
1800
1801
# ############# drawdowns.py ############# #
1802
1803
1804
ts2 = pd.DataFrame({
1805
'a': [2, 1, 3, 1, 4, 1],
1806
'b': [1, 2, 1, 3, 1, 4],
1807
'c': [1, 2, 3, 2, 1, 2],
1808
'd': [1, 2, 3, 4, 5, 6]
1809
}, index=[
1810
datetime(2020, 1, 1),
1811
datetime(2020, 1, 2),
1812
datetime(2020, 1, 3),
1813
datetime(2020, 1, 4),
1814
datetime(2020, 1, 5),
1815
datetime(2020, 1, 6)
1816
])
1817
1818
drawdowns = vbt.Drawdowns.from_ts(ts2, wrapper_kwargs=dict(freq='1 days'))
1819
drawdowns_grouped = vbt.Drawdowns.from_ts(ts2, wrapper_kwargs=dict(freq='1 days', group_by=group_by))
1820
1821
1822
class TestDrawdowns:
1823
def test_mapped_fields(self):
1824
for name in drawdown_dt.names:
1825
np.testing.assert_array_equal(
1826
getattr(drawdowns, name).values,
1827
drawdowns.values[name]
1828
)
1829
1830
def test_ts(self):
1831
pd.testing.assert_frame_equal(
1832
drawdowns.ts,
1833
ts2
1834
)
1835
pd.testing.assert_series_equal(
1836
drawdowns['a'].ts,
1837
ts2['a']
1838
)
1839
pd.testing.assert_frame_equal(
1840
drawdowns_grouped['g1'].ts,
1841
ts2[['a', 'b']]
1842
)
1843
assert drawdowns.replace(ts=None)['a'].ts is None
1844
1845
def test_from_ts(self):
1846
record_arrays_close(
1847
drawdowns.values,
1848
np.array([
1849
(0, 0, 0, 1, 1, 2, 2.0, 1.0, 3.0, 1), (1, 0, 2, 3, 3, 4, 3.0, 1.0, 4.0, 1),
1850
(2, 0, 4, 5, 5, 5, 4.0, 1.0, 1.0, 0), (3, 1, 1, 2, 2, 3, 2.0, 1.0, 3.0, 1),
1851
(4, 1, 3, 4, 4, 5, 3.0, 1.0, 4.0, 1), (5, 2, 2, 3, 4, 5, 3.0, 1.0, 2.0, 0)
1852
], dtype=drawdown_dt)
1853
)
1854
assert drawdowns.wrapper.freq == day_dt
1855
pd.testing.assert_index_equal(
1856
drawdowns_grouped.wrapper.grouper.group_by,
1857
group_by
1858
)
1859
1860
def test_records_readable(self):
1861
records_readable = drawdowns.records_readable
1862
1863
np.testing.assert_array_equal(
1864
records_readable['Drawdown Id'].values,
1865
np.array([
1866
0, 1, 2, 3, 4, 5
1867
])
1868
)
1869
np.testing.assert_array_equal(
1870
records_readable['Column'].values,
1871
np.array([
1872
'a', 'a', 'a', 'b', 'b', 'c'
1873
])
1874
)
1875
np.testing.assert_array_equal(
1876
records_readable['Peak Timestamp'].values,
1877
np.array([
1878
'2020-01-01T00:00:00.000000000', '2020-01-03T00:00:00.000000000',
1879
'2020-01-05T00:00:00.000000000', '2020-01-02T00:00:00.000000000',
1880
'2020-01-04T00:00:00.000000000', '2020-01-03T00:00:00.000000000'
1881
], dtype='datetime64[ns]')
1882
)
1883
np.testing.assert_array_equal(
1884
records_readable['Start Timestamp'].values,
1885
np.array([
1886
'2020-01-02T00:00:00.000000000', '2020-01-04T00:00:00.000000000',
1887
'2020-01-06T00:00:00.000000000', '2020-01-03T00:00:00.000000000',
1888
'2020-01-05T00:00:00.000000000', '2020-01-04T00:00:00.000000000'
1889
], dtype='datetime64[ns]')
1890
)
1891
np.testing.assert_array_equal(
1892
records_readable['Valley Timestamp'].values,
1893
np.array([
1894
'2020-01-02T00:00:00.000000000', '2020-01-04T00:00:00.000000000',
1895
'2020-01-06T00:00:00.000000000', '2020-01-03T00:00:00.000000000',
1896
'2020-01-05T00:00:00.000000000', '2020-01-05T00:00:00.000000000'
1897
], dtype='datetime64[ns]')
1898
)
1899
np.testing.assert_array_equal(
1900
records_readable['End Timestamp'].values,
1901
np.array([
1902
'2020-01-03T00:00:00.000000000', '2020-01-05T00:00:00.000000000',
1903
'2020-01-06T00:00:00.000000000', '2020-01-04T00:00:00.000000000',
1904
'2020-01-06T00:00:00.000000000', '2020-01-06T00:00:00.000000000'
1905
], dtype='datetime64[ns]')
1906
)
1907
np.testing.assert_array_equal(
1908
records_readable['Peak Value'].values,
1909
np.array([
1910
2., 3., 4., 2., 3., 3.
1911
])
1912
)
1913
np.testing.assert_array_equal(
1914
records_readable['Valley Value'].values,
1915
np.array([
1916
1., 1., 1., 1., 1., 1.
1917
])
1918
)
1919
np.testing.assert_array_equal(
1920
records_readable['End Value'].values,
1921
np.array([
1922
3., 4., 1., 3., 4., 2.
1923
])
1924
)
1925
np.testing.assert_array_equal(
1926
records_readable['Status'].values,
1927
np.array([
1928
'Recovered', 'Recovered', 'Active', 'Recovered', 'Recovered', 'Active'
1929
])
1930
)
1931
1932
def test_drawdown(self):
1933
np.testing.assert_array_almost_equal(
1934
drawdowns['a'].drawdown.values,
1935
np.array([-0.5, -0.66666667, -0.75])
1936
)
1937
np.testing.assert_array_almost_equal(
1938
drawdowns.drawdown.values,
1939
np.array([-0.5, -0.66666667, -0.75, -0.5, -0.66666667, -0.66666667])
1940
)
1941
pd.testing.assert_frame_equal(
1942
drawdowns.drawdown.to_pd(),
1943
pd.DataFrame(
1944
np.array([
1945
[np.nan, np.nan, np.nan, np.nan],
1946
[np.nan, np.nan, np.nan, np.nan],
1947
[-0.5, np.nan, np.nan, np.nan],
1948
[np.nan, -0.5, np.nan, np.nan],
1949
[-0.66666669, np.nan, np.nan, np.nan],
1950
[-0.75, -0.66666669, -0.66666669, np.nan]
1951
]),
1952
index=ts2.index,
1953
columns=ts2.columns
1954
)
1955
)
1956
1957
def test_avg_drawdown(self):
1958
assert drawdowns['a'].avg_drawdown() == -0.6388888888888888
1959
pd.testing.assert_series_equal(
1960
drawdowns.avg_drawdown(),
1961
pd.Series(
1962
np.array([-0.63888889, -0.58333333, -0.66666667, np.nan]),
1963
index=wrapper.columns
1964
).rename('avg_drawdown')
1965
)
1966
pd.testing.assert_series_equal(
1967
drawdowns_grouped.avg_drawdown(),
1968
pd.Series(
1969
np.array([-0.6166666666666666, -0.6666666666666666]),
1970
index=pd.Index(['g1', 'g2'], dtype='object')
1971
).rename('avg_drawdown')
1972
)
1973
1974
def test_max_drawdown(self):
1975
assert drawdowns['a'].max_drawdown() == -0.75
1976
pd.testing.assert_series_equal(
1977
drawdowns.max_drawdown(),
1978
pd.Series(
1979
np.array([-0.75, -0.66666667, -0.66666667, np.nan]),
1980
index=wrapper.columns
1981
).rename('max_drawdown')
1982
)
1983
pd.testing.assert_series_equal(
1984
drawdowns_grouped.max_drawdown(),
1985
pd.Series(
1986
np.array([-0.75, -0.6666666666666666]),
1987
index=pd.Index(['g1', 'g2'], dtype='object')
1988
).rename('max_drawdown')
1989
)
1990
1991
def test_recovery_return(self):
1992
np.testing.assert_array_almost_equal(
1993
drawdowns['a'].recovery_return.values,
1994
np.array([2., 3., 0.])
1995
)
1996
np.testing.assert_array_almost_equal(
1997
drawdowns.recovery_return.values,
1998
np.array([2., 3., 0., 2., 3., 1.])
1999
)
2000
pd.testing.assert_frame_equal(
2001
drawdowns.recovery_return.to_pd(),
2002
pd.DataFrame(
2003
np.array([
2004
[np.nan, np.nan, np.nan, np.nan],
2005
[np.nan, np.nan, np.nan, np.nan],
2006
[2.0, np.nan, np.nan, np.nan],
2007
[np.nan, 2.0, np.nan, np.nan],
2008
[3.0, np.nan, np.nan, np.nan],
2009
[0.0, 3.0, 1.0, np.nan]
2010
]),
2011
index=ts2.index,
2012
columns=ts2.columns
2013
)
2014
)
2015
2016
def test_avg_recovery_return(self):
2017
assert drawdowns['a'].avg_recovery_return() == 1.6666666666666667
2018
pd.testing.assert_series_equal(
2019
drawdowns.avg_recovery_return(),
2020
pd.Series(
2021
np.array([1.6666666666666667, 2.5, 1.0, np.nan]),
2022
index=wrapper.columns
2023
).rename('avg_recovery_return')
2024
)
2025
pd.testing.assert_series_equal(
2026
drawdowns_grouped.avg_recovery_return(),
2027
pd.Series(
2028
np.array([2.0, 1.0]),
2029
index=pd.Index(['g1', 'g2'], dtype='object')
2030
).rename('avg_recovery_return')
2031
)
2032
2033
def test_max_recovery_return(self):
2034
assert drawdowns['a'].max_recovery_return() == 3.0
2035
pd.testing.assert_series_equal(
2036
drawdowns.max_recovery_return(),
2037
pd.Series(
2038
np.array([3.0, 3.0, 1.0, np.nan]),
2039
index=wrapper.columns
2040
).rename('max_recovery_return')
2041
)
2042
pd.testing.assert_series_equal(
2043
drawdowns_grouped.max_recovery_return(),
2044
pd.Series(
2045
np.array([3.0, 1.0]),
2046
index=pd.Index(['g1', 'g2'], dtype='object')
2047
).rename('max_recovery_return')
2048
)
2049
2050
def test_duration(self):
2051
np.testing.assert_array_almost_equal(
2052
drawdowns['a'].duration.values,
2053
np.array([1, 1, 1])
2054
)
2055
np.testing.assert_array_almost_equal(
2056
drawdowns.duration.values,
2057
np.array([1, 1, 1, 1, 1, 3])
2058
)
2059
2060
def test_avg_duration(self):
2061
assert drawdowns['a'].avg_duration() == pd.Timedelta('1 days 00:00:00')
2062
pd.testing.assert_series_equal(
2063
drawdowns.avg_duration(),
2064
pd.Series(
2065
np.array([86400000000000, 86400000000000, 259200000000000, 'NaT'], dtype='timedelta64[ns]'),
2066
index=wrapper.columns
2067
).rename('avg_duration')
2068
)
2069
pd.testing.assert_series_equal(
2070
drawdowns_grouped.avg_duration(),
2071
pd.Series(
2072
np.array([86400000000000, 259200000000000], dtype='timedelta64[ns]'),
2073
index=pd.Index(['g1', 'g2'], dtype='object')
2074
).rename('avg_duration')
2075
)
2076
2077
def test_max_duration(self):
2078
assert drawdowns['a'].max_duration() == pd.Timedelta('1 days 00:00:00')
2079
pd.testing.assert_series_equal(
2080
drawdowns.max_duration(),
2081
pd.Series(
2082
np.array([86400000000000, 86400000000000, 259200000000000, 'NaT'], dtype='timedelta64[ns]'),
2083
index=wrapper.columns
2084
).rename('max_duration')
2085
)
2086
pd.testing.assert_series_equal(
2087
drawdowns_grouped.max_duration(),
2088
pd.Series(
2089
np.array([86400000000000, 259200000000000], dtype='timedelta64[ns]'),
2090
index=pd.Index(['g1', 'g2'], dtype='object')
2091
).rename('max_duration')
2092
)
2093
2094
def test_coverage(self):
2095
assert drawdowns['a'].coverage() == 0.5
2096
pd.testing.assert_series_equal(
2097
drawdowns.coverage(),
2098
pd.Series(
2099
np.array([0.5, 0.3333333333333333, 0.5, np.nan]),
2100
index=ts2.columns
2101
).rename('coverage')
2102
)
2103
pd.testing.assert_series_equal(
2104
drawdowns_grouped.coverage(),
2105
pd.Series(
2106
np.array([0.4166666666666667, 0.25]),
2107
index=pd.Index(['g1', 'g2'], dtype='object')
2108
).rename('coverage')
2109
)
2110
2111
def test_decline_duration(self):
2112
np.testing.assert_array_almost_equal(
2113
drawdowns['a'].decline_duration.values,
2114
np.array([1., 1., 1.])
2115
)
2116
np.testing.assert_array_almost_equal(
2117
drawdowns.decline_duration.values,
2118
np.array([1., 1., 1., 1., 1., 2.])
2119
)
2120
2121
def test_recovery_duration(self):
2122
np.testing.assert_array_almost_equal(
2123
drawdowns['a'].recovery_duration.values,
2124
np.array([1, 1, 0])
2125
)
2126
np.testing.assert_array_almost_equal(
2127
drawdowns.recovery_duration.values,
2128
np.array([1, 1, 0, 1, 1, 1])
2129
)
2130
2131
def test_recovery_duration_ratio(self):
2132
np.testing.assert_array_almost_equal(
2133
drawdowns['a'].recovery_duration_ratio.values,
2134
np.array([1., 1., 0.])
2135
)
2136
np.testing.assert_array_almost_equal(
2137
drawdowns.recovery_duration_ratio.values,
2138
np.array([1., 1., 0., 1., 1., 0.5])
2139
)
2140
2141
def test_active_records(self):
2142
assert isinstance(drawdowns.active, vbt.Drawdowns)
2143
assert drawdowns.active.wrapper == drawdowns.wrapper
2144
record_arrays_close(
2145
drawdowns['a'].active.values,
2146
np.array([
2147
(2, 0, 4, 5, 5, 5, 4., 1., 1., 0)
2148
], dtype=drawdown_dt)
2149
)
2150
record_arrays_close(
2151
drawdowns['a'].active.values,
2152
drawdowns.active['a'].values
2153
)
2154
record_arrays_close(
2155
drawdowns.active.values,
2156
np.array([
2157
(2, 0, 4, 5, 5, 5, 4.0, 1.0, 1.0, 0), (5, 2, 2, 3, 4, 5, 3.0, 1.0, 2.0, 0)
2158
], dtype=drawdown_dt)
2159
)
2160
2161
def test_recovered_records(self):
2162
assert isinstance(drawdowns.recovered, vbt.Drawdowns)
2163
assert drawdowns.recovered.wrapper == drawdowns.wrapper
2164
record_arrays_close(
2165
drawdowns['a'].recovered.values,
2166
np.array([
2167
(0, 0, 0, 1, 1, 2, 2.0, 1.0, 3.0, 1), (1, 0, 2, 3, 3, 4, 3.0, 1.0, 4.0, 1)
2168
], dtype=drawdown_dt)
2169
)
2170
record_arrays_close(
2171
drawdowns['a'].recovered.values,
2172
drawdowns.recovered['a'].values
2173
)
2174
record_arrays_close(
2175
drawdowns.recovered.values,
2176
np.array([
2177
(0, 0, 0, 1, 1, 2, 2.0, 1.0, 3.0, 1), (1, 0, 2, 3, 3, 4, 3.0, 1.0, 4.0, 1),
2178
(3, 1, 1, 2, 2, 3, 2.0, 1.0, 3.0, 1), (4, 1, 3, 4, 4, 5, 3.0, 1.0, 4.0, 1)
2179
], dtype=drawdown_dt)
2180
)
2181
2182
def test_active_drawdown(self):
2183
assert drawdowns['a'].active_drawdown() == -0.75
2184
pd.testing.assert_series_equal(
2185
drawdowns.active_drawdown(),
2186
pd.Series(
2187
np.array([-0.75, np.nan, -0.3333333333333333, np.nan]),
2188
index=wrapper.columns
2189
).rename('active_drawdown')
2190
)
2191
with pytest.raises(Exception):
2192
drawdowns_grouped.active_drawdown()
2193
2194
def test_active_duration(self):
2195
assert drawdowns['a'].active_duration() == np.timedelta64(86400000000000)
2196
pd.testing.assert_series_equal(
2197
drawdowns.active_duration(),
2198
pd.Series(
2199
np.array([86400000000000, 'NaT', 259200000000000, 'NaT'], dtype='timedelta64[ns]'),
2200
index=wrapper.columns
2201
).rename('active_duration')
2202
)
2203
with pytest.raises(Exception):
2204
drawdowns_grouped.active_duration()
2205
2206
def test_active_recovery(self):
2207
assert drawdowns['a'].active_recovery() == 0.
2208
pd.testing.assert_series_equal(
2209
drawdowns.active_recovery(),
2210
pd.Series(
2211
np.array([0., np.nan, 0.5, np.nan]),
2212
index=wrapper.columns
2213
).rename('active_recovery')
2214
)
2215
with pytest.raises(Exception):
2216
drawdowns_grouped.active_recovery()
2217
2218
def test_active_recovery_return(self):
2219
assert drawdowns['a'].active_recovery_return() == 0.
2220
pd.testing.assert_series_equal(
2221
drawdowns.active_recovery_return(),
2222
pd.Series(
2223
np.array([0., np.nan, 1., np.nan]),
2224
index=wrapper.columns
2225
).rename('active_recovery_return')
2226
)
2227
with pytest.raises(Exception):
2228
drawdowns_grouped.active_recovery_return()
2229
2230
def test_active_recovery_duration(self):
2231
assert drawdowns['a'].active_recovery_duration() == pd.Timedelta('0 days 00:00:00')
2232
pd.testing.assert_series_equal(
2233
drawdowns.active_recovery_duration(),
2234
pd.Series(
2235
np.array([0, 'NaT', 86400000000000, 'NaT'], dtype='timedelta64[ns]'),
2236
index=wrapper.columns
2237
).rename('active_recovery_duration')
2238
)
2239
with pytest.raises(Exception):
2240
drawdowns_grouped.active_recovery_duration()
2241
2242
def test_stats(self):
2243
stats_index = pd.Index([
2244
'Start', 'End', 'Period', 'Coverage [%]', 'Total Records',
2245
'Total Recovered Drawdowns', 'Total Active Drawdowns',
2246
'Active Drawdown [%]', 'Active Duration', 'Active Recovery [%]',
2247
'Active Recovery Return [%]', 'Active Recovery Duration',
2248
'Max Drawdown [%]', 'Avg Drawdown [%]', 'Max Drawdown Duration',
2249
'Avg Drawdown Duration', 'Max Recovery Return [%]',
2250
'Avg Recovery Return [%]', 'Max Recovery Duration',
2251
'Avg Recovery Duration', 'Avg Recovery Duration Ratio'
2252
], dtype='object')
2253
pd.testing.assert_series_equal(
2254
drawdowns.stats(),
2255
pd.Series([
2256
pd.Timestamp('2020-01-01 00:00:00'), pd.Timestamp('2020-01-06 00:00:00'),
2257
pd.Timedelta('6 days 00:00:00'), 44.444444444444436, 1.5, 1.0, 0.5,
2258
54.166666666666664, pd.Timedelta('2 days 00:00:00'), 25.0, 50.0,
2259
pd.Timedelta('0 days 12:00:00'), 66.66666666666666, 58.33333333333333,
2260
pd.Timedelta('1 days 00:00:00'), pd.Timedelta('1 days 00:00:00'), 300.0, 250.0,
2261
pd.Timedelta('1 days 00:00:00'), pd.Timedelta('1 days 00:00:00'), 1.0
2262
],
2263
index=stats_index,
2264
name='agg_func_mean'
2265
)
2266
)
2267
pd.testing.assert_series_equal(
2268
drawdowns.stats(settings=dict(incl_active=True)),
2269
pd.Series([
2270
pd.Timestamp('2020-01-01 00:00:00'), pd.Timestamp('2020-01-06 00:00:00'),
2271
pd.Timedelta('6 days 00:00:00'), 44.444444444444436, 1.5, 1.0, 0.5,
2272
54.166666666666664, pd.Timedelta('2 days 00:00:00'), 25.0, 50.0,
2273
pd.Timedelta('0 days 12:00:00'), 69.44444444444444, 62.962962962962955,
2274
pd.Timedelta('1 days 16:00:00'), pd.Timedelta('1 days 16:00:00'), 300.0, 250.0,
2275
pd.Timedelta('1 days 00:00:00'), pd.Timedelta('1 days 00:00:00'), 1.0
2276
],
2277
index=stats_index,
2278
name='agg_func_mean'
2279
)
2280
)
2281
pd.testing.assert_series_equal(
2282
drawdowns.stats(column='a'),
2283
pd.Series([
2284
pd.Timestamp('2020-01-01 00:00:00'), pd.Timestamp('2020-01-06 00:00:00'),
2285
pd.Timedelta('6 days 00:00:00'), 50.0, 3, 2, 1, 75.0, pd.Timedelta('1 days 00:00:00'),
2286
0.0, 0.0, pd.Timedelta('0 days 00:00:00'), 66.66666666666666, 58.33333333333333,
2287
pd.Timedelta('1 days 00:00:00'), pd.Timedelta('1 days 00:00:00'), 300.0, 250.0,
2288
pd.Timedelta('1 days 00:00:00'), pd.Timedelta('1 days 00:00:00'), 1.0
2289
],
2290
index=stats_index,
2291
name='a'
2292
)
2293
)
2294
pd.testing.assert_series_equal(
2295
drawdowns.stats(column='g1', group_by=group_by),
2296
pd.Series([
2297
pd.Timestamp('2020-01-01 00:00:00'), pd.Timestamp('2020-01-06 00:00:00'),
2298
pd.Timedelta('6 days 00:00:00'), 41.66666666666667, 5, 4, 1, 66.66666666666666,
2299
58.33333333333333, pd.Timedelta('1 days 00:00:00'), pd.Timedelta('1 days 00:00:00'),
2300
300.0, 250.0, pd.Timedelta('1 days 00:00:00'), pd.Timedelta('1 days 00:00:00'), 1.0
2301
],
2302
index=pd.Index([
2303
'Start', 'End', 'Period', 'Coverage [%]', 'Total Records',
2304
'Total Recovered Drawdowns', 'Total Active Drawdowns',
2305
'Max Drawdown [%]', 'Avg Drawdown [%]', 'Max Drawdown Duration',
2306
'Avg Drawdown Duration', 'Max Recovery Return [%]',
2307
'Avg Recovery Return [%]', 'Max Recovery Duration',
2308
'Avg Recovery Duration', 'Avg Recovery Duration Ratio'
2309
], dtype='object'),
2310
name='g1'
2311
)
2312
)
2313
pd.testing.assert_series_equal(
2314
drawdowns['c'].stats(),
2315
drawdowns.stats(column='c')
2316
)
2317
pd.testing.assert_series_equal(
2318
drawdowns['c'].stats(),
2319
drawdowns.stats(column='c', group_by=False)
2320
)
2321
pd.testing.assert_series_equal(
2322
drawdowns_grouped['g2'].stats(),
2323
drawdowns_grouped.stats(column='g2')
2324
)
2325
pd.testing.assert_series_equal(
2326
drawdowns_grouped['g2'].stats(),
2327
drawdowns.stats(column='g2', group_by=group_by)
2328
)
2329
stats_df = drawdowns.stats(agg_func=None)
2330
assert stats_df.shape == (4, 21)
2331
pd.testing.assert_index_equal(stats_df.index, drawdowns.wrapper.columns)
2332
pd.testing.assert_index_equal(stats_df.columns, stats_index)
2333
2334
2335
# ############# orders.py ############# #
2336
2337
close = pd.Series([1, 2, 3, 4, 5, 6, 7, 8], index=[
2338
datetime(2020, 1, 1),
2339
datetime(2020, 1, 2),
2340
datetime(2020, 1, 3),
2341
datetime(2020, 1, 4),
2342
datetime(2020, 1, 5),
2343
datetime(2020, 1, 6),
2344
datetime(2020, 1, 7),
2345
datetime(2020, 1, 8)
2346
]).vbt.tile(4, keys=['a', 'b', 'c', 'd'])
2347
2348
size = np.full(close.shape, np.nan, dtype=np.float64)
2349
size[:, 0] = [1, 0.1, -1, -0.1, np.nan, 1, -1, 2]
2350
size[:, 1] = [-1, -0.1, 1, 0.1, np.nan, -1, 1, -2]
2351
size[:, 2] = [1, 0.1, -1, -0.1, np.nan, 1, -2, 2]
2352
orders = vbt.Portfolio.from_orders(close, size, fees=0.01, freq='1 days').orders
2353
orders_grouped = orders.regroup(group_by)
2354
2355
2356
class TestOrders:
2357
def test_mapped_fields(self):
2358
for name in order_dt.names:
2359
np.testing.assert_array_equal(
2360
getattr(orders, name).values,
2361
orders.values[name]
2362
)
2363
2364
def test_close(self):
2365
pd.testing.assert_frame_equal(
2366
orders.close,
2367
close
2368
)
2369
pd.testing.assert_series_equal(
2370
orders['a'].close,
2371
close['a']
2372
)
2373
pd.testing.assert_frame_equal(
2374
orders_grouped['g1'].close,
2375
close[['a', 'b']]
2376
)
2377
assert orders.replace(close=None)['a'].close is None
2378
2379
def test_records_readable(self):
2380
records_readable = orders.records_readable
2381
2382
np.testing.assert_array_equal(
2383
records_readable['Order Id'].values,
2384
np.array([
2385
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20
2386
])
2387
)
2388
np.testing.assert_array_equal(
2389
records_readable['Timestamp'].values,
2390
np.array([
2391
'2020-01-01T00:00:00.000000000', '2020-01-02T00:00:00.000000000',
2392
'2020-01-03T00:00:00.000000000', '2020-01-04T00:00:00.000000000',
2393
'2020-01-06T00:00:00.000000000', '2020-01-07T00:00:00.000000000',
2394
'2020-01-08T00:00:00.000000000', '2020-01-01T00:00:00.000000000',
2395
'2020-01-02T00:00:00.000000000', '2020-01-03T00:00:00.000000000',
2396
'2020-01-04T00:00:00.000000000', '2020-01-06T00:00:00.000000000',
2397
'2020-01-07T00:00:00.000000000', '2020-01-08T00:00:00.000000000',
2398
'2020-01-01T00:00:00.000000000', '2020-01-02T00:00:00.000000000',
2399
'2020-01-03T00:00:00.000000000', '2020-01-04T00:00:00.000000000',
2400
'2020-01-06T00:00:00.000000000', '2020-01-07T00:00:00.000000000',
2401
'2020-01-08T00:00:00.000000000'
2402
], dtype='datetime64[ns]')
2403
)
2404
np.testing.assert_array_equal(
2405
records_readable['Column'].values,
2406
np.array([
2407
'a', 'a', 'a', 'a', 'a', 'a', 'a', 'b', 'b', 'b', 'b', 'b', 'b',
2408
'b', 'c', 'c', 'c', 'c', 'c', 'c', 'c'
2409
])
2410
)
2411
np.testing.assert_array_equal(
2412
records_readable['Size'].values,
2413
np.array([
2414
1.0, 0.1, 1.0, 0.1, 1.0, 1.0, 2.0, 1.0, 0.1, 1.0, 0.1, 1.0, 1.0,
2415
2.0, 1.0, 0.1, 1.0, 0.1, 1.0, 2.0, 2.0
2416
])
2417
)
2418
np.testing.assert_array_equal(
2419
records_readable['Price'].values,
2420
np.array([
2421
1.0, 2.0, 3.0, 4.0, 6.0, 7.0, 8.0, 1.0, 2.0, 3.0, 4.0, 6.0, 7.0,
2422
8.0, 1.0, 2.0, 3.0, 4.0, 6.0, 7.0, 8.0
2423
])
2424
)
2425
np.testing.assert_array_equal(
2426
records_readable['Fees'].values,
2427
np.array([
2428
0.01, 0.002, 0.03, 0.004, 0.06, 0.07, 0.16, 0.01, 0.002, 0.03,
2429
0.004, 0.06, 0.07, 0.16, 0.01, 0.002, 0.03, 0.004, 0.06, 0.14,
2430
0.16
2431
])
2432
)
2433
np.testing.assert_array_equal(
2434
records_readable['Side'].values,
2435
np.array([
2436
'Buy', 'Buy', 'Sell', 'Sell', 'Buy', 'Sell', 'Buy', 'Sell', 'Sell',
2437
'Buy', 'Buy', 'Sell', 'Buy', 'Sell', 'Buy', 'Buy', 'Sell', 'Sell',
2438
'Buy', 'Sell', 'Buy'
2439
])
2440
)
2441
2442
def test_buy_records(self):
2443
assert isinstance(orders.buy, vbt.Orders)
2444
assert orders.buy.wrapper == orders.wrapper
2445
record_arrays_close(
2446
orders['a'].buy.values,
2447
np.array([
2448
(0, 0, 0, 1., 1., 0.01, 0), (1, 0, 1, 0.1, 2., 0.002, 0),
2449
(4, 0, 5, 1., 6., 0.06, 0), (6, 0, 7, 2., 8., 0.16, 0)
2450
], dtype=order_dt)
2451
)
2452
record_arrays_close(
2453
orders['a'].buy.values,
2454
orders.buy['a'].values
2455
)
2456
record_arrays_close(
2457
orders.buy.values,
2458
np.array([
2459
(0, 0, 0, 1., 1., 0.01, 0), (1, 0, 1, 0.1, 2., 0.002, 0),
2460
(4, 0, 5, 1., 6., 0.06, 0), (6, 0, 7, 2., 8., 0.16, 0),
2461
(9, 1, 2, 1., 3., 0.03, 0), (10, 1, 3, 0.1, 4., 0.004, 0),
2462
(12, 1, 6, 1., 7., 0.07, 0), (14, 2, 0, 1., 1., 0.01, 0),
2463
(15, 2, 1, 0.1, 2., 0.002, 0), (18, 2, 5, 1., 6., 0.06, 0),
2464
(20, 2, 7, 2., 8., 0.16, 0)
2465
], dtype=order_dt)
2466
)
2467
2468
def test_sell_records(self):
2469
assert isinstance(orders.sell, vbt.Orders)
2470
assert orders.sell.wrapper == orders.wrapper
2471
record_arrays_close(
2472
orders['a'].sell.values,
2473
np.array([
2474
(2, 0, 2, 1., 3., 0.03, 1), (3, 0, 3, 0.1, 4., 0.004, 1),
2475
(5, 0, 6, 1., 7., 0.07, 1)
2476
], dtype=order_dt)
2477
)
2478
record_arrays_close(
2479
orders['a'].sell.values,
2480
orders.sell['a'].values
2481
)
2482
record_arrays_close(
2483
orders.sell.values,
2484
np.array([
2485
(2, 0, 2, 1., 3., 0.03, 1), (3, 0, 3, 0.1, 4., 0.004, 1),
2486
(5, 0, 6, 1., 7., 0.07, 1), (7, 1, 0, 1., 1., 0.01, 1),
2487
(8, 1, 1, 0.1, 2., 0.002, 1), (11, 1, 5, 1., 6., 0.06, 1),
2488
(13, 1, 7, 2., 8., 0.16, 1), (16, 2, 2, 1., 3., 0.03, 1),
2489
(17, 2, 3, 0.1, 4., 0.004, 1), (19, 2, 6, 2., 7., 0.14, 1)
2490
], dtype=order_dt)
2491
)
2492
2493
def test_stats(self):
2494
stats_index = pd.Index([
2495
'Start', 'End', 'Period', 'Total Records', 'Total Buy Orders', 'Total Sell Orders',
2496
'Min Size', 'Max Size', 'Avg Size', 'Avg Buy Size', 'Avg Sell Size',
2497
'Avg Buy Price', 'Avg Sell Price', 'Total Fees', 'Min Fees', 'Max Fees',
2498
'Avg Fees', 'Avg Buy Fees', 'Avg Sell Fees'
2499
], dtype='object')
2500
pd.testing.assert_series_equal(
2501
orders.stats(),
2502
pd.Series([
2503
pd.Timestamp('2020-01-01 00:00:00'), pd.Timestamp('2020-01-08 00:00:00'),
2504
pd.Timedelta('8 days 00:00:00'), 5.25, 2.75, 2.5, 0.10000000000000002, 2.0,
2505
0.9333333333333335, 0.9166666666666666, 0.9194444444444446, 4.388888888888889,
2506
4.527777777777779, 0.26949999999999996, 0.002, 0.16, 0.051333333333333335,
2507
0.050222222222222224, 0.050222222222222224
2508
],
2509
index=stats_index,
2510
name='agg_func_mean'
2511
)
2512
)
2513
pd.testing.assert_series_equal(
2514
orders.stats(column='a'),
2515
pd.Series([
2516
pd.Timestamp('2020-01-01 00:00:00'), pd.Timestamp('2020-01-08 00:00:00'),
2517
pd.Timedelta('8 days 00:00:00'), 7, 4, 3, 0.1, 2.0, 0.8857142857142858,
2518
1.025, 0.7000000000000001, 4.25, 4.666666666666667, 0.33599999999999997,
2519
0.002, 0.16, 0.047999999999999994, 0.057999999999999996, 0.03466666666666667
2520
],
2521
index=stats_index,
2522
name='a'
2523
)
2524
)
2525
pd.testing.assert_series_equal(
2526
orders.stats(column='g1', group_by=group_by),
2527
pd.Series([
2528
pd.Timestamp('2020-01-01 00:00:00'), pd.Timestamp('2020-01-08 00:00:00'),
2529
pd.Timedelta('8 days 00:00:00'), 14, 7, 7, 0.1, 2.0, 0.8857142857142858,
2530
0.8857142857142856, 0.8857142857142858, 4.428571428571429, 4.428571428571429,
2531
0.672, 0.002, 0.16, 0.048, 0.048, 0.047999999999999994
2532
],
2533
index=stats_index,
2534
name='g1'
2535
)
2536
)
2537
pd.testing.assert_series_equal(
2538
orders['c'].stats(),
2539
orders.stats(column='c')
2540
)
2541
pd.testing.assert_series_equal(
2542
orders['c'].stats(),
2543
orders.stats(column='c', group_by=False)
2544
)
2545
pd.testing.assert_series_equal(
2546
orders_grouped['g2'].stats(),
2547
orders_grouped.stats(column='g2')
2548
)
2549
pd.testing.assert_series_equal(
2550
orders_grouped['g2'].stats(),
2551
orders.stats(column='g2', group_by=group_by)
2552
)
2553
stats_df = orders.stats(agg_func=None)
2554
assert stats_df.shape == (4, 19)
2555
pd.testing.assert_index_equal(stats_df.index, orders.wrapper.columns)
2556
pd.testing.assert_index_equal(stats_df.columns, stats_index)
2557
2558
2559
# ############# trades.py ############# #
2560
2561
exit_trades = vbt.ExitTrades.from_orders(orders)
2562
exit_trades_grouped = vbt.ExitTrades.from_orders(orders_grouped)
2563
2564
2565
class TestExitTrades:
2566
def test_mapped_fields(self):
2567
for name in trade_dt.names:
2568
if name == 'return':
2569
np.testing.assert_array_equal(
2570
getattr(exit_trades, 'returns').values,
2571
exit_trades.values[name]
2572
)
2573
else:
2574
np.testing.assert_array_equal(
2575
getattr(exit_trades, name).values,
2576
exit_trades.values[name]
2577
)
2578
2579
def test_close(self):
2580
pd.testing.assert_frame_equal(
2581
exit_trades.close,
2582
close
2583
)
2584
pd.testing.assert_series_equal(
2585
exit_trades['a'].close,
2586
close['a']
2587
)
2588
pd.testing.assert_frame_equal(
2589
exit_trades_grouped['g1'].close,
2590
close[['a', 'b']]
2591
)
2592
assert exit_trades.replace(close=None)['a'].close is None
2593
2594
def test_records_arr(self):
2595
record_arrays_close(
2596
exit_trades.values,
2597
np.array([
2598
(0, 0, 1., 0, 1.09090909, 0.01090909, 2, 3., 0.03, 1.86818182, 1.7125, 0, 1, 0),
2599
(1, 0, 0.1, 0, 1.09090909, 0.00109091, 3, 4., 0.004, 0.28581818, 2.62, 0, 1, 0),
2600
(2, 0, 1., 5, 6., 0.06, 6, 7., 0.07, 0.87, 0.145, 0, 1, 1),
2601
(3, 0, 2., 7, 8., 0.16, 7, 8., 0., -0.16, -0.01, 0, 0, 2),
2602
(4, 1, 1., 0, 1.09090909, 0.01090909, 2, 3., 0.03, -1.95, -1.7875, 1, 1, 3),
2603
(5, 1, 0.1, 0, 1.09090909, 0.00109091, 3, 4., 0.004, -0.296, -2.71333333, 1, 1, 3),
2604
(6, 1, 1., 5, 6., 0.06, 6, 7., 0.07, -1.13, -0.18833333, 1, 1, 4),
2605
(7, 1, 2., 7, 8., 0.16, 7, 8., 0., -0.16, -0.01, 1, 0, 5),
2606
(8, 2, 1., 0, 1.09090909, 0.01090909, 2, 3., 0.03, 1.86818182, 1.7125, 0, 1, 6),
2607
(9, 2, 0.1, 0, 1.09090909, 0.00109091, 3, 4., 0.004, 0.28581818, 2.62, 0, 1, 6),
2608
(10, 2, 1., 5, 6., 0.06, 6, 7., 0.07, 0.87, 0.145, 0, 1, 7),
2609
(11, 2, 1., 6, 7., 0.07, 7, 8., 0.08, -1.15, -0.16428571, 1, 1, 8),
2610
(12, 2, 1., 7, 8., 0.08, 7, 8., 0., -0.08, -0.01, 0, 0, 9)
2611
], dtype=trade_dt)
2612
)
2613
reversed_col_orders = orders.replace(records_arr=np.concatenate((
2614
orders.values[orders.values['col'] == 2],
2615
orders.values[orders.values['col'] == 1],
2616
orders.values[orders.values['col'] == 0]
2617
)))
2618
record_arrays_close(
2619
vbt.ExitTrades.from_orders(reversed_col_orders).values,
2620
exit_trades.values
2621
)
2622
2623
def test_records_readable(self):
2624
records_readable = exit_trades.records_readable
2625
2626
np.testing.assert_array_equal(
2627
records_readable['Exit Trade Id'].values,
2628
np.array([
2629
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12
2630
])
2631
)
2632
np.testing.assert_array_equal(
2633
records_readable['Column'].values,
2634
np.array([
2635
'a', 'a', 'a', 'a', 'b', 'b', 'b', 'b', 'c', 'c', 'c', 'c', 'c'
2636
])
2637
)
2638
np.testing.assert_array_equal(
2639
records_readable['Size'].values,
2640
np.array([
2641
1.0, 0.10000000000000009, 1.0, 2.0, 1.0, 0.10000000000000009, 1.0,
2642
2.0, 1.0, 0.10000000000000009, 1.0, 1.0, 1.0
2643
])
2644
)
2645
np.testing.assert_array_equal(
2646
records_readable['Entry Timestamp'].values,
2647
np.array([
2648
'2020-01-01T00:00:00.000000000', '2020-01-01T00:00:00.000000000',
2649
'2020-01-06T00:00:00.000000000', '2020-01-08T00:00:00.000000000',
2650
'2020-01-01T00:00:00.000000000', '2020-01-01T00:00:00.000000000',
2651
'2020-01-06T00:00:00.000000000', '2020-01-08T00:00:00.000000000',
2652
'2020-01-01T00:00:00.000000000', '2020-01-01T00:00:00.000000000',
2653
'2020-01-06T00:00:00.000000000', '2020-01-07T00:00:00.000000000',
2654
'2020-01-08T00:00:00.000000000'
2655
], dtype='datetime64[ns]')
2656
)
2657
np.testing.assert_array_equal(
2658
records_readable['Avg Entry Price'].values,
2659
np.array([
2660
1.0909090909090908, 1.0909090909090908, 6.0, 8.0,
2661
1.0909090909090908, 1.0909090909090908, 6.0, 8.0,
2662
1.0909090909090908, 1.0909090909090908, 6.0, 7.0, 8.0
2663
])
2664
)
2665
np.testing.assert_array_equal(
2666
records_readable['Entry Fees'].values,
2667
np.array([
2668
0.010909090909090908, 0.0010909090909090918, 0.06, 0.16,
2669
0.010909090909090908, 0.0010909090909090918, 0.06, 0.16,
2670
0.010909090909090908, 0.0010909090909090918, 0.06, 0.07, 0.08
2671
])
2672
)
2673
np.testing.assert_array_equal(
2674
records_readable['Exit Timestamp'].values,
2675
np.array([
2676
'2020-01-03T00:00:00.000000000', '2020-01-04T00:00:00.000000000',
2677
'2020-01-07T00:00:00.000000000', '2020-01-08T00:00:00.000000000',
2678
'2020-01-03T00:00:00.000000000', '2020-01-04T00:00:00.000000000',
2679
'2020-01-07T00:00:00.000000000', '2020-01-08T00:00:00.000000000',
2680
'2020-01-03T00:00:00.000000000', '2020-01-04T00:00:00.000000000',
2681
'2020-01-07T00:00:00.000000000', '2020-01-08T00:00:00.000000000',
2682
'2020-01-08T00:00:00.000000000'
2683
], dtype='datetime64[ns]')
2684
)
2685
np.testing.assert_array_equal(
2686
records_readable['Avg Exit Price'].values,
2687
np.array([
2688
3.0, 4.0, 7.0, 8.0, 3.0, 4.0, 7.0, 8.0, 3.0, 4.0, 7.0, 8.0, 8.0
2689
])
2690
)
2691
np.testing.assert_array_equal(
2692
records_readable['Exit Fees'].values,
2693
np.array([
2694
0.03, 0.004, 0.07, 0.0, 0.03, 0.004, 0.07, 0.0, 0.03, 0.004, 0.07, 0.08, 0.0
2695
])
2696
)
2697
np.testing.assert_array_equal(
2698
records_readable['PnL'].values,
2699
np.array([
2700
1.8681818181818182, 0.2858181818181821, 0.8699999999999999, -0.16,
2701
-1.9500000000000002, -0.29600000000000026, -1.1300000000000001,
2702
-0.16, 1.8681818181818182, 0.2858181818181821, 0.8699999999999999,
2703
-1.1500000000000001, -0.08
2704
])
2705
)
2706
np.testing.assert_array_equal(
2707
records_readable['Return'].values,
2708
np.array([
2709
1.7125000000000001, 2.62, 0.145, -0.01, -1.7875000000000003,
2710
-2.7133333333333334, -0.18833333333333335, -0.01,
2711
1.7125000000000001, 2.62, 0.145, -0.1642857142857143, -0.01
2712
])
2713
)
2714
np.testing.assert_array_equal(
2715
records_readable['Direction'].values,
2716
np.array([
2717
'Long', 'Long', 'Long', 'Long', 'Short', 'Short', 'Short',
2718
'Short', 'Long', 'Long', 'Long', 'Short', 'Long'
2719
])
2720
)
2721
np.testing.assert_array_equal(
2722
records_readable['Status'].values,
2723
np.array([
2724
'Closed', 'Closed', 'Closed', 'Open', 'Closed', 'Closed', 'Closed',
2725
'Open', 'Closed', 'Closed', 'Closed', 'Closed', 'Open'
2726
])
2727
)
2728
np.testing.assert_array_equal(
2729
records_readable['Position Id'].values,
2730
np.array([
2731
0, 0, 1, 2, 3, 3, 4, 5, 6, 6, 7, 8, 9
2732
])
2733
)
2734
2735
def test_duration(self):
2736
np.testing.assert_array_almost_equal(
2737
exit_trades['a'].duration.values,
2738
np.array([2, 3, 1, 1])
2739
)
2740
np.testing.assert_array_almost_equal(
2741
exit_trades.duration.values,
2742
np.array([2, 3, 1, 1, 2, 3, 1, 1, 2, 3, 1, 1, 1])
2743
)
2744
2745
def test_winning_records(self):
2746
assert isinstance(exit_trades.winning, vbt.ExitTrades)
2747
assert exit_trades.winning.wrapper == exit_trades.wrapper
2748
record_arrays_close(
2749
exit_trades['a'].winning.values,
2750
np.array([
2751
(0, 0, 1., 0, 1.09090909, 0.01090909, 2, 3., 0.03, 1.86818182, 1.7125, 0, 1, 0),
2752
(1, 0, 0.1, 0, 1.09090909, 0.00109091, 3, 4., 0.004, 0.28581818, 2.62, 0, 1, 0),
2753
(2, 0, 1., 5, 6., 0.06, 6, 7., 0.07, 0.87, 0.145, 0, 1, 1)
2754
], dtype=trade_dt)
2755
)
2756
record_arrays_close(
2757
exit_trades['a'].winning.values,
2758
exit_trades.winning['a'].values
2759
)
2760
record_arrays_close(
2761
exit_trades.winning.values,
2762
np.array([
2763
(0, 0, 1., 0, 1.09090909, 0.01090909, 2, 3., 0.03, 1.86818182, 1.7125, 0, 1, 0),
2764
(1, 0, 0.1, 0, 1.09090909, 0.00109091, 3, 4., 0.004, 0.28581818, 2.62, 0, 1, 0),
2765
(2, 0, 1., 5, 6., 0.06, 6, 7., 0.07, 0.87, 0.145, 0, 1, 1),
2766
(8, 2, 1., 0, 1.09090909, 0.01090909, 2, 3., 0.03, 1.86818182, 1.7125, 0, 1, 6),
2767
(9, 2, 0.1, 0, 1.09090909, 0.00109091, 3, 4., 0.004, 0.28581818, 2.62, 0, 1, 6),
2768
(10, 2, 1., 5, 6., 0.06, 6, 7., 0.07, 0.87, 0.145, 0, 1, 7)
2769
], dtype=trade_dt)
2770
)
2771
2772
def test_losing_records(self):
2773
assert isinstance(exit_trades.losing, vbt.ExitTrades)
2774
assert exit_trades.losing.wrapper == exit_trades.wrapper
2775
record_arrays_close(
2776
exit_trades['a'].losing.values,
2777
np.array([
2778
(3, 0, 2., 7, 8., 0.16, 7, 8., 0., -0.16, -0.01, 0, 0, 2)
2779
], dtype=trade_dt)
2780
)
2781
record_arrays_close(
2782
exit_trades['a'].losing.values,
2783
exit_trades.losing['a'].values
2784
)
2785
record_arrays_close(
2786
exit_trades.losing.values,
2787
np.array([
2788
(3, 0, 2., 7, 8., 0.16, 7, 8., 0., -0.16, -0.01, 0, 0, 2),
2789
(4, 1, 1., 0, 1.09090909, 0.01090909, 2, 3., 0.03, -1.95, -1.7875, 1, 1, 3),
2790
(5, 1, 0.1, 0, 1.09090909, 0.00109091, 3, 4., 0.004, -0.296, -2.71333333, 1, 1, 3),
2791
(6, 1, 1., 5, 6., 0.06, 6, 7., 0.07, -1.13, -0.18833333, 1, 1, 4),
2792
(7, 1, 2., 7, 8., 0.16, 7, 8., 0., -0.16, -0.01, 1, 0, 5),
2793
(11, 2, 1., 6, 7., 0.07, 7, 8., 0.08, -1.15, -0.16428571, 1, 1, 8),
2794
(12, 2, 1., 7, 8., 0.08, 7, 8., 0., -0.08, -0.01, 0, 0, 9)
2795
], dtype=trade_dt)
2796
)
2797
2798
def test_win_rate(self):
2799
assert exit_trades['a'].win_rate() == 0.75
2800
pd.testing.assert_series_equal(
2801
exit_trades.win_rate(),
2802
pd.Series(
2803
np.array([0.75, 0., 0.6, np.nan]),
2804
index=close.columns
2805
).rename('win_rate')
2806
)
2807
pd.testing.assert_series_equal(
2808
exit_trades_grouped.win_rate(),
2809
pd.Series(
2810
np.array([0.375, 0.6]),
2811
index=pd.Index(['g1', 'g2'], dtype='object')
2812
).rename('win_rate')
2813
)
2814
2815
def test_winning_streak(self):
2816
np.testing.assert_array_almost_equal(
2817
exit_trades['a'].winning_streak.values,
2818
np.array([1, 2, 3, 0])
2819
)
2820
np.testing.assert_array_almost_equal(
2821
exit_trades.winning_streak.values,
2822
np.array([1, 2, 3, 0, 0, 0, 0, 0, 1, 2, 3, 0, 0])
2823
)
2824
2825
def test_losing_streak(self):
2826
np.testing.assert_array_almost_equal(
2827
exit_trades['a'].losing_streak.values,
2828
np.array([0, 0, 0, 1])
2829
)
2830
np.testing.assert_array_almost_equal(
2831
exit_trades.losing_streak.values,
2832
np.array([0, 0, 0, 1, 1, 2, 3, 4, 0, 0, 0, 1, 2])
2833
)
2834
2835
def test_profit_factor(self):
2836
assert exit_trades['a'].profit_factor() == 18.9
2837
pd.testing.assert_series_equal(
2838
exit_trades.profit_factor(),
2839
pd.Series(
2840
np.array([18.9, 0., 2.45853659, np.nan]),
2841
index=ts2.columns
2842
).rename('profit_factor')
2843
)
2844
pd.testing.assert_series_equal(
2845
exit_trades_grouped.profit_factor(),
2846
pd.Series(
2847
np.array([0.81818182, 2.45853659]),
2848
index=pd.Index(['g1', 'g2'], dtype='object')
2849
).rename('profit_factor')
2850
)
2851
2852
def test_expectancy(self):
2853
assert exit_trades['a'].expectancy() == 0.716
2854
pd.testing.assert_series_equal(
2855
exit_trades.expectancy(),
2856
pd.Series(
2857
np.array([0.716, -0.884, 0.3588, np.nan]),
2858
index=ts2.columns
2859
).rename('expectancy')
2860
)
2861
pd.testing.assert_series_equal(
2862
exit_trades_grouped.expectancy(),
2863
pd.Series(
2864
np.array([-0.084, 0.3588]),
2865
index=pd.Index(['g1', 'g2'], dtype='object')
2866
).rename('expectancy')
2867
)
2868
2869
def test_sqn(self):
2870
assert exit_trades['a'].sqn() == 1.634155521947584
2871
pd.testing.assert_series_equal(
2872
exit_trades.sqn(),
2873
pd.Series(
2874
np.array([1.63415552, -2.13007307, 0.71660403, np.nan]),
2875
index=ts2.columns
2876
).rename('sqn')
2877
)
2878
pd.testing.assert_series_equal(
2879
exit_trades_grouped.sqn(),
2880
pd.Series(
2881
np.array([-0.20404671, 0.71660403]),
2882
index=pd.Index(['g1', 'g2'], dtype='object')
2883
).rename('sqn')
2884
)
2885
2886
def test_long_records(self):
2887
assert isinstance(exit_trades.long, vbt.ExitTrades)
2888
assert exit_trades.long.wrapper == exit_trades.wrapper
2889
record_arrays_close(
2890
exit_trades['a'].long.values,
2891
np.array([
2892
(0, 0, 1., 0, 1.09090909, 0.01090909, 2, 3., 0.03, 1.86818182, 1.7125, 0, 1, 0),
2893
(1, 0, 0.1, 0, 1.09090909, 0.00109091, 3, 4., 0.004, 0.28581818, 2.62, 0, 1, 0),
2894
(2, 0, 1., 5, 6., 0.06, 6, 7., 0.07, 0.87, 0.145, 0, 1, 1),
2895
(3, 0, 2., 7, 8., 0.16, 7, 8., 0., -0.16, -0.01, 0, 0, 2)
2896
], dtype=trade_dt)
2897
)
2898
record_arrays_close(
2899
exit_trades['a'].long.values,
2900
exit_trades.long['a'].values
2901
)
2902
record_arrays_close(
2903
exit_trades.long.values,
2904
np.array([
2905
(0, 0, 1., 0, 1.09090909, 0.01090909, 2, 3., 0.03, 1.86818182, 1.7125, 0, 1, 0),
2906
(1, 0, 0.1, 0, 1.09090909, 0.00109091, 3, 4., 0.004, 0.28581818, 2.62, 0, 1, 0),
2907
(2, 0, 1., 5, 6., 0.06, 6, 7., 0.07, 0.87, 0.145, 0, 1, 1),
2908
(3, 0, 2., 7, 8., 0.16, 7, 8., 0., -0.16, -0.01, 0, 0, 2),
2909
(8, 2, 1., 0, 1.09090909, 0.01090909, 2, 3., 0.03, 1.86818182, 1.7125, 0, 1, 6),
2910
(9, 2, 0.1, 0, 1.09090909, 0.00109091, 3, 4., 0.004, 0.28581818, 2.62, 0, 1, 6),
2911
(10, 2, 1., 5, 6., 0.06, 6, 7., 0.07, 0.87, 0.145, 0, 1, 7),
2912
(12, 2, 1., 7, 8., 0.08, 7, 8., 0., -0.08, -0.01, 0, 0, 9)
2913
], dtype=trade_dt)
2914
)
2915
2916
def test_short_records(self):
2917
assert isinstance(exit_trades.short, vbt.ExitTrades)
2918
assert exit_trades.short.wrapper == exit_trades.wrapper
2919
record_arrays_close(
2920
exit_trades['a'].short.values,
2921
np.array([], dtype=trade_dt)
2922
)
2923
record_arrays_close(
2924
exit_trades['a'].short.values,
2925
exit_trades.short['a'].values
2926
)
2927
record_arrays_close(
2928
exit_trades.short.values,
2929
np.array([
2930
(4, 1, 1., 0, 1.09090909, 0.01090909, 2, 3., 0.03, -1.95, -1.7875, 1, 1, 3),
2931
(5, 1, 0.1, 0, 1.09090909, 0.00109091, 3, 4., 0.004, -0.296, -2.71333333, 1, 1, 3),
2932
(6, 1, 1., 5, 6., 0.06, 6, 7., 0.07, -1.13, -0.18833333, 1, 1, 4),
2933
(7, 1, 2., 7, 8., 0.16, 7, 8., 0., -0.16, -0.01, 1, 0, 5),
2934
(11, 2, 1., 6, 7., 0.07, 7, 8., 0.08, -1.15, -0.16428571, 1, 1, 8)
2935
], dtype=trade_dt)
2936
)
2937
2938
def test_open_records(self):
2939
assert isinstance(exit_trades.open, vbt.ExitTrades)
2940
assert exit_trades.open.wrapper == exit_trades.wrapper
2941
record_arrays_close(
2942
exit_trades['a'].open.values,
2943
np.array([
2944
(3, 0, 2., 7, 8., 0.16, 7, 8., 0., -0.16, -0.01, 0, 0, 2)
2945
], dtype=trade_dt)
2946
)
2947
record_arrays_close(
2948
exit_trades['a'].open.values,
2949
exit_trades.open['a'].values
2950
)
2951
record_arrays_close(
2952
exit_trades.open.values,
2953
np.array([
2954
(3, 0, 2., 7, 8., 0.16, 7, 8., 0., -0.16, -0.01, 0, 0, 2),
2955
(7, 1, 2., 7, 8., 0.16, 7, 8., 0., -0.16, -0.01, 1, 0, 5),
2956
(12, 2, 1., 7, 8., 0.08, 7, 8., 0., -0.08, -0.01, 0, 0, 9)
2957
], dtype=trade_dt)
2958
)
2959
2960
def test_closed_records(self):
2961
assert isinstance(exit_trades.closed, vbt.ExitTrades)
2962
assert exit_trades.closed.wrapper == exit_trades.wrapper
2963
record_arrays_close(
2964
exit_trades['a'].closed.values,
2965
np.array([
2966
(0, 0, 1., 0, 1.09090909, 0.01090909, 2, 3., 0.03, 1.86818182, 1.7125, 0, 1, 0),
2967
(1, 0, 0.1, 0, 1.09090909, 0.00109091, 3, 4., 0.004, 0.28581818, 2.62, 0, 1, 0),
2968
(2, 0, 1., 5, 6., 0.06, 6, 7., 0.07, 0.87, 0.145, 0, 1, 1)
2969
], dtype=trade_dt)
2970
)
2971
record_arrays_close(
2972
exit_trades['a'].closed.values,
2973
exit_trades.closed['a'].values
2974
)
2975
record_arrays_close(
2976
exit_trades.closed.values,
2977
np.array([
2978
(0, 0, 1., 0, 1.09090909, 0.01090909, 2, 3., 0.03, 1.86818182, 1.7125, 0, 1, 0),
2979
(1, 0, 0.1, 0, 1.09090909, 0.00109091, 3, 4., 0.004, 0.28581818, 2.62, 0, 1, 0),
2980
(2, 0, 1., 5, 6., 0.06, 6, 7., 0.07, 0.87, 0.145, 0, 1, 1),
2981
(4, 1, 1., 0, 1.09090909, 0.01090909, 2, 3., 0.03, -1.95, -1.7875, 1, 1, 3),
2982
(5, 1, 0.1, 0, 1.09090909, 0.00109091, 3, 4., 0.004, -0.296, -2.71333333, 1, 1, 3),
2983
(6, 1, 1., 5, 6., 0.06, 6, 7., 0.07, -1.13, -0.18833333, 1, 1, 4),
2984
(8, 2, 1., 0, 1.09090909, 0.01090909, 2, 3., 0.03, 1.86818182, 1.7125, 0, 1, 6),
2985
(9, 2, 0.1, 0, 1.09090909, 0.00109091, 3, 4., 0.004, 0.28581818, 2.62, 0, 1, 6),
2986
(10, 2, 1., 5, 6., 0.06, 6, 7., 0.07, 0.87, 0.145, 0, 1, 7),
2987
(11, 2, 1., 6, 7., 0.07, 7, 8., 0.08, -1.15, -0.16428571, 1, 1, 8)
2988
], dtype=trade_dt)
2989
)
2990
2991
def test_stats(self):
2992
stats_index = pd.Index([
2993
'Start', 'End', 'Period', 'First Trade Start', 'Last Trade End',
2994
'Coverage', 'Overlap Coverage', 'Total Records', 'Total Long Trades',
2995
'Total Short Trades', 'Total Closed Trades', 'Total Open Trades',
2996
'Open Trade PnL', 'Win Rate [%]', 'Max Win Streak', 'Max Loss Streak',
2997
'Best Trade [%]', 'Worst Trade [%]', 'Avg Winning Trade [%]',
2998
'Avg Losing Trade [%]', 'Avg Winning Trade Duration',
2999
'Avg Losing Trade Duration', 'Profit Factor', 'Expectancy', 'SQN'
3000
], dtype='object')
3001
pd.testing.assert_series_equal(
3002
exit_trades.stats(),
3003
pd.Series([
3004
pd.Timestamp('2020-01-01 00:00:00'), pd.Timestamp('2020-01-08 00:00:00'),
3005
pd.Timedelta('8 days 00:00:00'), pd.Timestamp('2020-01-01 00:00:00'),
3006
pd.Timestamp('2020-01-08 00:00:00'), pd.Timedelta('5 days 08:00:00'),
3007
pd.Timedelta('2 days 00:00:00'), 3.25, 2.0, 1.25, 2.5, 0.75, -0.1,
3008
58.333333333333336, 2.0, 1.3333333333333333, 168.38888888888889,
3009
-91.08730158730158, 149.25, -86.3670634920635, pd.Timedelta('2 days 00:00:00'),
3010
pd.Timedelta('1 days 12:00:00'), np.inf, 0.11705555555555548, 0.18931590012681135
3011
],
3012
index=stats_index,
3013
name='agg_func_mean'
3014
)
3015
)
3016
pd.testing.assert_series_equal(
3017
exit_trades.stats(settings=dict(incl_open=True)),
3018
pd.Series([
3019
pd.Timestamp('2020-01-01 00:00:00'), pd.Timestamp('2020-01-08 00:00:00'),
3020
pd.Timedelta('8 days 00:00:00'), pd.Timestamp('2020-01-01 00:00:00'),
3021
pd.Timestamp('2020-01-08 00:00:00'), pd.Timedelta('5 days 08:00:00'),
3022
pd.Timedelta('2 days 00:00:00'), 3.25, 2.0, 1.25, 2.5, 0.75, -0.1,
3023
58.333333333333336, 2.0, 2.3333333333333335, 174.33333333333334,
3024
-96.25396825396825, 149.25, -42.39781746031746, pd.Timedelta('2 days 00:00:00'),
3025
pd.Timedelta('1 days 06:00:00'), 7.11951219512195, 0.06359999999999993, 0.07356215977397455
3026
],
3027
index=stats_index,
3028
name='agg_func_mean'
3029
)
3030
)
3031
pd.testing.assert_series_equal(
3032
exit_trades.stats(column='a'),
3033
pd.Series([
3034
pd.Timestamp('2020-01-01 00:00:00'), pd.Timestamp('2020-01-08 00:00:00'),
3035
pd.Timedelta('8 days 00:00:00'), pd.Timestamp('2020-01-01 00:00:00'),
3036
pd.Timestamp('2020-01-08 00:00:00'), pd.Timedelta('5 days 00:00:00'),
3037
pd.Timedelta('2 days 00:00:00'), 4, 4, 0, 3, 1, -0.16, 100.0, 3, 0,
3038
262.0, 14.499999999999998, 149.25, np.nan, pd.Timedelta('2 days 00:00:00'),
3039
pd.NaT, np.inf, 1.008, 2.181955050824476
3040
],
3041
index=stats_index,
3042
name='a'
3043
)
3044
)
3045
pd.testing.assert_series_equal(
3046
exit_trades.stats(column='g1', group_by=group_by),
3047
pd.Series([
3048
pd.Timestamp('2020-01-01 00:00:00'), pd.Timestamp('2020-01-08 00:00:00'),
3049
pd.Timedelta('8 days 00:00:00'), pd.Timestamp('2020-01-01 00:00:00'),
3050
pd.Timestamp('2020-01-08 00:00:00'), pd.Timedelta('5 days 00:00:00'),
3051
pd.Timedelta('5 days 00:00:00'), 8, 4, 4, 6, 2, -0.32, 50.0, 3, 3, 262.0,
3052
-271.3333333333333, 149.25, -156.30555555555557, pd.Timedelta('2 days 00:00:00'),
3053
pd.Timedelta('2 days 00:00:00'), 0.895734597156398, -0.058666666666666756, -0.10439051512510047
3054
],
3055
index=stats_index,
3056
name='g1'
3057
)
3058
)
3059
pd.testing.assert_index_equal(
3060
exit_trades.stats(tags='trades').index,
3061
pd.Index([
3062
'First Trade Start', 'Last Trade End', 'Total Long Trades',
3063
'Total Short Trades', 'Total Closed Trades', 'Total Open Trades',
3064
'Open Trade PnL', 'Win Rate [%]', 'Max Win Streak', 'Max Loss Streak',
3065
'Best Trade [%]', 'Worst Trade [%]', 'Avg Winning Trade [%]',
3066
'Avg Losing Trade [%]', 'Avg Winning Trade Duration',
3067
'Avg Losing Trade Duration', 'Profit Factor', 'Expectancy', 'SQN'
3068
], dtype='object')
3069
)
3070
pd.testing.assert_series_equal(
3071
exit_trades['c'].stats(),
3072
exit_trades.stats(column='c')
3073
)
3074
pd.testing.assert_series_equal(
3075
exit_trades['c'].stats(),
3076
exit_trades.stats(column='c', group_by=False)
3077
)
3078
pd.testing.assert_series_equal(
3079
exit_trades_grouped['g2'].stats(),
3080
exit_trades_grouped.stats(column='g2')
3081
)
3082
pd.testing.assert_series_equal(
3083
exit_trades_grouped['g2'].stats(),
3084
exit_trades.stats(column='g2', group_by=group_by)
3085
)
3086
stats_df = exit_trades.stats(agg_func=None)
3087
assert stats_df.shape == (4, 25)
3088
pd.testing.assert_index_equal(stats_df.index, exit_trades.wrapper.columns)
3089
pd.testing.assert_index_equal(stats_df.columns, stats_index)
3090
3091
3092
entry_trades = vbt.EntryTrades.from_orders(orders)
3093
entry_trades_grouped = vbt.EntryTrades.from_orders(orders_grouped)
3094
3095
3096
class TestEntryTrades:
3097
def test_records_arr(self):
3098
record_arrays_close(
3099
entry_trades.values,
3100
np.array([
3101
(0, 0, 1.0, 0, 1.0, 0.01, 3, 3.0909090909090904, 0.03090909090909091, 2.05, 2.05, 0, 1, 0),
3102
(1, 0, 0.1, 1, 2.0, 0.002, 3, 3.0909090909090904, 0.003090909090909091,
3103
0.10399999999999998, 0.5199999999999999, 0, 1, 0),
3104
(2, 0, 1.0, 5, 6.0, 0.06, 6, 7.0, 0.07, 0.8699999999999999, 0.145, 0, 1, 1),
3105
(3, 0, 2.0, 7, 8.0, 0.16, 7, 8.0, 0.0, -0.16, -0.01, 0, 0, 2),
3106
(4, 1, 1.0, 0, 1.0, 0.01, 3, 3.0909090909090904, 0.03090909090909091,
3107
-2.131818181818181, -2.131818181818181, 1, 1, 3),
3108
(5, 1, 0.1, 1, 2.0, 0.002, 3, 3.0909090909090904, 0.003090909090909091,
3109
-0.11418181818181816, -0.5709090909090908, 1, 1, 3),
3110
(6, 1, 1.0, 5, 6.0, 0.06, 6, 7.0, 0.07, -1.1300000000000001, -0.18833333333333335, 1, 1, 4),
3111
(7, 1, 2.0, 7, 8.0, 0.16, 7, 8.0, 0.0, -0.16, -0.01, 1, 0, 5),
3112
(8, 2, 1.0, 0, 1.0, 0.01, 3, 3.0909090909090904, 0.03090909090909091, 2.05, 2.05, 0, 1, 6),
3113
(9, 2, 0.1, 1, 2.0, 0.002, 3, 3.0909090909090904, 0.003090909090909091,
3114
0.10399999999999998, 0.5199999999999999, 0, 1, 6),
3115
(10, 2, 1.0, 5, 6.0, 0.06, 6, 7.0, 0.07, 0.8699999999999999, 0.145, 0, 1, 7),
3116
(11, 2, 1.0, 6, 7.0, 0.07, 7, 8.0, 0.08, -1.1500000000000001, -0.1642857142857143, 1, 1, 8),
3117
(12, 2, 1.0, 7, 8.0, 0.08, 7, 8.0, 0.0, -0.08, -0.01, 0, 0, 9)
3118
], dtype=trade_dt)
3119
)
3120
reversed_col_orders = orders.replace(records_arr=np.concatenate((
3121
orders.values[orders.values['col'] == 2],
3122
orders.values[orders.values['col'] == 1],
3123
orders.values[orders.values['col'] == 0]
3124
)))
3125
record_arrays_close(
3126
vbt.EntryTrades.from_orders(reversed_col_orders).values,
3127
entry_trades.values
3128
)
3129
3130
def test_records_readable(self):
3131
records_readable = entry_trades.records_readable
3132
3133
np.testing.assert_array_equal(
3134
records_readable['Entry Trade Id'].values,
3135
np.array([
3136
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12
3137
])
3138
)
3139
np.testing.assert_array_equal(
3140
records_readable['Position Id'].values,
3141
np.array([
3142
0, 0, 1, 2, 3, 3, 4, 5, 6, 6, 7, 8, 9
3143
])
3144
)
3145
3146
3147
positions = vbt.Positions.from_trades(exit_trades)
3148
positions_grouped = vbt.Positions.from_trades(exit_trades_grouped)
3149
3150
3151
class TestPositions:
3152
def test_records_arr(self):
3153
record_arrays_close(
3154
positions.values,
3155
np.array([
3156
(0, 0, 1.1, 0, 1.09090909, 0.012, 3, 3.09090909, 0.034, 2.154, 1.795, 0, 1, 0),
3157
(1, 0, 1., 5, 6., 0.06, 6, 7., 0.07, 0.87, 0.145, 0, 1, 1),
3158
(2, 0, 2., 7, 8., 0.16, 7, 8., 0., -0.16, -0.01, 0, 0, 2),
3159
(3, 1, 1.1, 0, 1.09090909, 0.012, 3, 3.09090909, 0.034, -2.246, -1.87166667, 1, 1, 3),
3160
(4, 1, 1., 5, 6., 0.06, 6, 7., 0.07, -1.13, -0.18833333, 1, 1, 4),
3161
(5, 1, 2., 7, 8., 0.16, 7, 8., 0., -0.16, -0.01, 1, 0, 5),
3162
(6, 2, 1.1, 0, 1.09090909, 0.012, 3, 3.09090909, 0.034, 2.154, 1.795, 0, 1, 6),
3163
(7, 2, 1., 5, 6., 0.06, 6, 7., 0.07, 0.87, 0.145, 0, 1, 7),
3164
(8, 2, 1., 6, 7., 0.07, 7, 8., 0.08, -1.15, -0.16428571, 1, 1, 8),
3165
(9, 2, 1., 7, 8., 0.08, 7, 8., 0., -0.08, -0.01, 0, 0, 9)
3166
], dtype=trade_dt)
3167
)
3168
reversed_col_trades = exit_trades.replace(records_arr=np.concatenate((
3169
exit_trades.values[exit_trades.values['col'] == 2],
3170
exit_trades.values[exit_trades.values['col'] == 1],
3171
exit_trades.values[exit_trades.values['col'] == 0]
3172
)))
3173
record_arrays_close(
3174
vbt.Positions.from_trades(reversed_col_trades).values,
3175
positions.values
3176
)
3177
3178
def test_records_readable(self):
3179
records_readable = positions.records_readable
3180
3181
np.testing.assert_array_equal(
3182
records_readable['Position Id'].values,
3183
np.array([
3184
0, 1, 2, 3, 4, 5, 6, 7, 8, 9
3185
])
3186
)
3187
assert 'Parent Id' not in records_readable.columns
3188
3189
3190
# ############# logs.py ############# #
3191
3192
logs = vbt.Portfolio.from_orders(close, size, fees=0.01, log=True, freq='1 days').logs
3193
logs_grouped = logs.regroup(group_by)
3194
3195
3196
class TestLogs:
3197
def test_mapped_fields(self):
3198
for name in log_dt.names:
3199
np.testing.assert_array_equal(
3200
getattr(logs, name).values,
3201
logs.values[name]
3202
)
3203
3204
def test_records_readable(self):
3205
records_readable = logs.records_readable
3206
3207
np.testing.assert_array_equal(
3208
records_readable['Log Id'].values,
3209
np.array([
3210
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27,
3211
28, 29, 30, 31
3212
])
3213
)
3214
np.testing.assert_array_equal(
3215
records_readable['Timestamp'].values,
3216
np.array([
3217
'2020-01-01T00:00:00.000000000', '2020-01-02T00:00:00.000000000',
3218
'2020-01-03T00:00:00.000000000', '2020-01-04T00:00:00.000000000',
3219
'2020-01-05T00:00:00.000000000', '2020-01-06T00:00:00.000000000',
3220
'2020-01-07T00:00:00.000000000', '2020-01-08T00:00:00.000000000',
3221
'2020-01-01T00:00:00.000000000', '2020-01-02T00:00:00.000000000',
3222
'2020-01-03T00:00:00.000000000', '2020-01-04T00:00:00.000000000',
3223
'2020-01-05T00:00:00.000000000', '2020-01-06T00:00:00.000000000',
3224
'2020-01-07T00:00:00.000000000', '2020-01-08T00:00:00.000000000',
3225
'2020-01-01T00:00:00.000000000', '2020-01-02T00:00:00.000000000',
3226
'2020-01-03T00:00:00.000000000', '2020-01-04T00:00:00.000000000',
3227
'2020-01-05T00:00:00.000000000', '2020-01-06T00:00:00.000000000',
3228
'2020-01-07T00:00:00.000000000', '2020-01-08T00:00:00.000000000',
3229
'2020-01-01T00:00:00.000000000', '2020-01-02T00:00:00.000000000',
3230
'2020-01-03T00:00:00.000000000', '2020-01-04T00:00:00.000000000',
3231
'2020-01-05T00:00:00.000000000', '2020-01-06T00:00:00.000000000',
3232
'2020-01-07T00:00:00.000000000', '2020-01-08T00:00:00.000000000'
3233
], dtype='datetime64[ns]')
3234
)
3235
np.testing.assert_array_equal(
3236
records_readable['Column'].values,
3237
np.array([
3238
'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'b', 'b', 'b', 'b', 'b', 'b', 'b', 'b', 'c', 'c', 'c', 'c', 'c',
3239
'c', 'c', 'c', 'd', 'd', 'd', 'd', 'd', 'd', 'd', 'd'
3240
])
3241
)
3242
np.testing.assert_array_equal(
3243
records_readable['Group'].values,
3244
np.array([
3245
0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3
3246
])
3247
)
3248
np.testing.assert_array_equal(
3249
records_readable['Cash'].values,
3250
np.array([
3251
100.0, 98.99, 98.788, 101.758, 102.154, 102.154, 96.094, 103.024, 100.0, 100.99, 101.18799999999999,
3252
98.15799999999999, 97.75399999999999, 97.75399999999999, 103.69399999999999, 96.624, 100.0, 98.99,
3253
98.788, 101.758, 102.154, 102.154, 96.094, 109.954, 100.0, 100.0, 100.0, 100.0, 100.0, 100.0, 100.0,
3254
100.0
3255
])
3256
)
3257
np.testing.assert_array_equal(
3258
records_readable['Position'].values,
3259
np.array([
3260
0.0, 1.0, 1.1, 0.10000000000000009, 0.0, 0.0, 1.0, 0.0, 0.0, -1.0, -1.1, -0.10000000000000009, 0.0, 0.0,
3261
-1.0, 0.0, 0.0, 1.0, 1.1, 0.10000000000000009, 0.0, 0.0, 1.0, -1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
3262
0.0
3263
])
3264
)
3265
np.testing.assert_array_equal(
3266
records_readable['Debt'].values,
3267
np.array([
3268
0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 1.2, 0.10909090909090913, 0.0, 0.0, 6.0, 0.0, 0.0,
3269
0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 7.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0
3270
])
3271
)
3272
np.testing.assert_array_equal(
3273
records_readable['Free Cash'].values,
3274
np.array([
3275
100.0, 98.99, 98.788, 101.758, 102.154, 102.154, 96.094, 103.024, 100.0, 98.99, 98.788,
3276
97.93981818181818, 97.754, 97.754, 91.694, 96.624, 100.0, 98.99, 98.788, 101.758, 102.154, 102.154,
3277
96.094, 95.954, 100.0, 100.0, 100.0, 100.0, 100.0, 100.0, 100.0, 100.0
3278
])
3279
)
3280
np.testing.assert_array_equal(
3281
records_readable['Val Price'].values,
3282
np.array([
3283
1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 1.0, 2.0, 3.0, 4.0, 5.0,
3284
6.0, 7.0, 8.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0
3285
])
3286
)
3287
np.testing.assert_array_equal(
3288
records_readable['Value'].values,
3289
np.array([
3290
100.0, 100.99, 102.088, 102.158, 102.154, 102.154, 103.094, 103.024, 100.0, 98.99, 97.88799999999999,
3291
97.75799999999998, 97.75399999999999, 97.75399999999999, 96.69399999999999, 96.624, 100.0, 100.99,
3292
102.088, 102.158, 102.154, 102.154, 103.094, 101.954, 100.0, 100.0, 100.0, 100.0, 100.0, 100.0, 100.0,
3293
100.0
3294
])
3295
)
3296
np.testing.assert_array_equal(
3297
records_readable['Request Size'].values,
3298
np.array([
3299
1.0, 0.1, -1.0, -0.1, np.nan, 1.0, -1.0, 2.0, -1.0, -0.1, 1.0, 0.1, np.nan, -1.0, 1.0, -2.0, 1.0, 0.1,
3300
-1.0, -0.1, np.nan, 1.0, -2.0, 2.0, np.nan, np.nan, np.nan, np.nan, np.nan, np.nan, np.nan, np.nan
3301
])
3302
)
3303
np.testing.assert_array_equal(
3304
records_readable['Request Price'].values,
3305
np.array([
3306
1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 1.0, 2.0, 3.0, 4.0, 5.0,
3307
6.0, 7.0, 8.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0
3308
])
3309
)
3310
np.testing.assert_array_equal(
3311
records_readable['Request Size Type'].values,
3312
np.array([
3313
'Amount', 'Amount', 'Amount', 'Amount', 'Amount', 'Amount', 'Amount', 'Amount', 'Amount', 'Amount',
3314
'Amount', 'Amount', 'Amount', 'Amount', 'Amount', 'Amount', 'Amount', 'Amount', 'Amount', 'Amount',
3315
'Amount', 'Amount', 'Amount', 'Amount', 'Amount', 'Amount', 'Amount', 'Amount', 'Amount', 'Amount',
3316
'Amount', 'Amount'
3317
])
3318
)
3319
np.testing.assert_array_equal(
3320
records_readable['Request Direction'].values,
3321
np.array([
3322
'Both', 'Both', 'Both', 'Both', 'Both', 'Both', 'Both', 'Both', 'Both', 'Both', 'Both', 'Both',
3323
'Both', 'Both', 'Both', 'Both', 'Both', 'Both', 'Both', 'Both', 'Both', 'Both', 'Both', 'Both',
3324
'Both', 'Both', 'Both', 'Both', 'Both', 'Both', 'Both', 'Both'
3325
])
3326
)
3327
np.testing.assert_array_equal(
3328
records_readable['Request Fees'].values,
3329
np.array([
3330
0.01, 0.01, 0.01, 0.01, 0.01, 0.01, 0.01, 0.01, 0.01, 0.01, 0.01, 0.01, 0.01, 0.01, 0.01, 0.01, 0.01,
3331
0.01, 0.01, 0.01, 0.01, 0.01, 0.01, 0.01, 0.01, 0.01, 0.01, 0.01, 0.01, 0.01, 0.01, 0.01
3332
])
3333
)
3334
np.testing.assert_array_equal(
3335
records_readable['Request Fixed Fees'].values,
3336
np.array([
3337
0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
3338
0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0
3339
])
3340
)
3341
np.testing.assert_array_equal(
3342
records_readable['Request Slippage'].values,
3343
np.array([
3344
0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
3345
0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0
3346
])
3347
)
3348
np.testing.assert_array_equal(
3349
records_readable['Request Min Size'].values,
3350
np.array([
3351
1e-08, 1e-08, 1e-08, 1e-08, 1e-08, 1e-08, 1e-08, 1e-08, 1e-08, 1e-08, 1e-08, 1e-08, 1e-08, 1e-08, 1e-08,
3352
1e-08, 1e-08, 1e-08, 1e-08, 1e-08, 1e-08, 1e-08, 1e-08, 1e-08, 1e-08, 1e-08, 1e-08, 1e-08, 1e-08, 1e-08,
3353
1e-08, 1e-08
3354
])
3355
)
3356
np.testing.assert_array_equal(
3357
records_readable['Request Max Size'].values,
3358
np.array([
3359
np.inf, np.inf, np.inf, np.inf, np.inf, np.inf, np.inf, np.inf, np.inf, np.inf, np.inf, np.inf, np.inf,
3360
np.inf, np.inf, np.inf, np.inf, np.inf, np.inf, np.inf, np.inf, np.inf, np.inf, np.inf, np.inf, np.inf,
3361
np.inf, np.inf, np.inf, np.inf, np.inf, np.inf
3362
])
3363
)
3364
np.testing.assert_array_equal(
3365
records_readable['Request Size Granularity'].values,
3366
np.array([
3367
np.nan, np.nan, np.nan, np.nan, np.nan, np.nan, np.nan, np.nan, np.nan, np.nan, np.nan, np.nan, np.nan,
3368
np.nan, np.nan, np.nan, np.nan, np.nan, np.nan, np.nan, np.nan, np.nan, np.nan, np.nan, np.nan, np.nan,
3369
np.nan, np.nan, np.nan, np.nan, np.nan, np.nan
3370
])
3371
)
3372
np.testing.assert_array_equal(
3373
records_readable['Request Rejection Prob'].values,
3374
np.array([
3375
0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
3376
0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0
3377
])
3378
)
3379
np.testing.assert_array_equal(
3380
records_readable['Request Lock Cash'].values,
3381
np.array([
3382
False, False, False, False, False, False, False, False, False, False, False, False, False, False, False,
3383
False, False, False, False, False, False, False, False, False, False, False, False, False, False, False,
3384
False, False
3385
])
3386
)
3387
np.testing.assert_array_equal(
3388
records_readable['Request Allow Partial'].values,
3389
np.array([
3390
True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True,
3391
True, True, True, True, True, True, True, True, True, True, True, True, True, True, True
3392
])
3393
)
3394
np.testing.assert_array_equal(
3395
records_readable['Request Raise Rejection'].values,
3396
np.array([
3397
False, False, False, False, False, False, False, False, False, False, False, False, False, False, False,
3398
False, False, False, False, False, False, False, False, False, False, False, False, False, False, False,
3399
False, False
3400
])
3401
)
3402
np.testing.assert_array_equal(
3403
records_readable['Request Log'].values,
3404
np.array([
3405
True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True,
3406
True, True, True, True, True, True, True, True, True, True, True, True, True, True, True
3407
])
3408
)
3409
np.testing.assert_array_equal(
3410
records_readable['New Cash'].values,
3411
np.array([
3412
98.99, 98.788, 101.758, 102.154, 102.154, 96.094, 103.024, 86.864, 100.99, 101.18799999999999,
3413
98.15799999999999, 97.75399999999999, 97.75399999999999, 103.69399999999999, 96.624, 112.464, 98.99,
3414
98.788, 101.758, 102.154, 102.154, 96.094, 109.954, 93.794, 100.0, 100.0, 100.0, 100.0, 100.0, 100.0,
3415
100.0, 100.0
3416
])
3417
)
3418
np.testing.assert_array_equal(
3419
records_readable['New Position'].values,
3420
np.array([
3421
1.0, 1.1, 0.10000000000000009, 0.0, 0.0, 1.0, 0.0, 2.0, -1.0, -1.1, -0.10000000000000009, 0.0, 0.0,
3422
-1.0, 0.0, -2.0, 1.0, 1.1, 0.10000000000000009, 0.0, 0.0, 1.0, -1.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
3423
0.0, 0.0
3424
])
3425
)
3426
np.testing.assert_array_equal(
3427
records_readable['New Debt'].values,
3428
np.array([
3429
0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 1.2, 0.10909090909090913, 0.0, 0.0, 6.0, 0.0, 16.0, 0.0,
3430
0.0, 0.0, 0.0, 0.0, 0.0, 7.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0
3431
])
3432
)
3433
np.testing.assert_array_equal(
3434
records_readable['New Free Cash'].values,
3435
np.array([
3436
98.99, 98.788, 101.758, 102.154, 102.154, 96.094, 103.024, 86.864, 98.99, 98.788, 97.93981818181818,
3437
97.754, 97.754, 91.694, 96.624, 80.464, 98.99, 98.788, 101.758, 102.154, 102.154, 96.094, 95.954,
3438
93.794, 100.0, 100.0, 100.0, 100.0, 100.0, 100.0, 100.0, 100.0
3439
])
3440
)
3441
np.testing.assert_array_equal(
3442
records_readable['New Val Price'].values,
3443
np.array([
3444
1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 1.0, 2.0, 3.0, 4.0, 5.0,
3445
6.0, 7.0, 8.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0
3446
])
3447
)
3448
np.testing.assert_array_equal(
3449
records_readable['New Value'].values,
3450
np.array([
3451
100.0, 100.99, 102.088, 102.158, 102.154, 102.154, 103.094, 103.024, 100.0, 98.99, 97.88799999999999,
3452
97.75799999999998, 97.75399999999999, 97.75399999999999, 96.69399999999999, 96.624, 100.0, 100.99,
3453
102.088, 102.158, 102.154, 102.154, 103.094, 101.954, 100.0, 100.0, 100.0, 100.0, 100.0, 100.0, 100.0,
3454
100.0
3455
])
3456
)
3457
np.testing.assert_array_equal(
3458
records_readable['Result Size'].values,
3459
np.array([
3460
1.0, 0.1, 1.0, 0.1, np.nan, 1.0, 1.0, 2.0, 1.0, 0.1, 1.0, 0.1, np.nan, 1.0, 1.0, 2.0, 1.0, 0.1, 1.0,
3461
0.1, np.nan, 1.0, 2.0, 2.0, np.nan, np.nan, np.nan, np.nan, np.nan, np.nan, np.nan, np.nan
3462
])
3463
)
3464
np.testing.assert_array_equal(
3465
records_readable['Result Price'].values,
3466
np.array([
3467
1.0, 2.0, 3.0, 4.0, np.nan, 6.0, 7.0, 8.0, 1.0, 2.0, 3.0, 4.0, np.nan, 6.0, 7.0, 8.0, 1.0, 2.0, 3.0,
3468
4.0, np.nan, 6.0, 7.0, 8.0, np.nan, np.nan, np.nan, np.nan, np.nan, np.nan, np.nan, np.nan
3469
])
3470
)
3471
np.testing.assert_array_equal(
3472
records_readable['Result Fees'].values,
3473
np.array([
3474
0.01, 0.002, 0.03, 0.004, np.nan, 0.06, 0.07, 0.16, 0.01, 0.002, 0.03, 0.004, np.nan, 0.06, 0.07, 0.16,
3475
0.01, 0.002, 0.03, 0.004, np.nan, 0.06, 0.14, 0.16, np.nan, np.nan, np.nan, np.nan, np.nan, np.nan,
3476
np.nan, np.nan
3477
])
3478
)
3479
np.testing.assert_array_equal(
3480
records_readable['Result Side'].values,
3481
np.array([
3482
'Buy', 'Buy', 'Sell', 'Sell', None, 'Buy', 'Sell', 'Buy', 'Sell', 'Sell', 'Buy', 'Buy', None, 'Sell',
3483
'Buy', 'Sell', 'Buy', 'Buy', 'Sell', 'Sell', None, 'Buy', 'Sell', 'Buy', None, None, None, None, None,
3484
None, None, None
3485
])
3486
)
3487
np.testing.assert_array_equal(
3488
records_readable['Result Status'].values,
3489
np.array([
3490
'Filled', 'Filled', 'Filled', 'Filled', 'Ignored', 'Filled', 'Filled', 'Filled', 'Filled', 'Filled',
3491
'Filled', 'Filled', 'Ignored', 'Filled', 'Filled', 'Filled', 'Filled', 'Filled', 'Filled', 'Filled',
3492
'Ignored', 'Filled', 'Filled', 'Filled', 'Ignored', 'Ignored', 'Ignored', 'Ignored', 'Ignored',
3493
'Ignored', 'Ignored', 'Ignored'
3494
])
3495
)
3496
np.testing.assert_array_equal(
3497
records_readable['Result Status Info'].values,
3498
np.array([
3499
None, None, None, None, 'SizeNaN', None, None, None, None, None, None, None, 'SizeNaN', None, None,
3500
None, None, None, None, None, 'SizeNaN', None, None, None, 'SizeNaN', 'SizeNaN', 'SizeNaN', 'SizeNaN',
3501
'SizeNaN', 'SizeNaN', 'SizeNaN', 'SizeNaN'
3502
])
3503
)
3504
np.testing.assert_array_equal(
3505
records_readable['Order Id'].values,
3506
np.array([
3507
0, 1, 2, 3, -1, 4, 5, 6, 7, 8, 9, 10, -1, 11, 12, 13, 14, 15, 16, 17, -1, 18, 19, 20, -1, -1, -1, -1,
3508
-1, -1, -1, -1
3509
])
3510
)
3511
3512
def test_stats(self):
3513
stats_index = pd.Index([
3514
'Start', 'End', 'Period', 'Total Records', 'Status Counts: None',
3515
'Status Counts: Filled', 'Status Counts: Ignored',
3516
'Status Counts: Rejected', 'Status Info Counts: None',
3517
'Status Info Counts: SizeNaN'
3518
], dtype='object')
3519
pd.testing.assert_series_equal(
3520
logs.stats(),
3521
pd.Series([
3522
pd.Timestamp('2020-01-01 00:00:00'), pd.Timestamp('2020-01-08 00:00:00'),
3523
pd.Timedelta('8 days 00:00:00'), 8.0, 0.0, 5.25, 2.75, 0.0, 5.25, 2.75
3524
],
3525
index=stats_index,
3526
name='agg_func_mean'
3527
)
3528
)
3529
pd.testing.assert_series_equal(
3530
logs.stats(column='a'),
3531
pd.Series([
3532
pd.Timestamp('2020-01-01 00:00:00'), pd.Timestamp('2020-01-08 00:00:00'),
3533
pd.Timedelta('8 days 00:00:00'), 8, 0, 7, 1, 0, 7, 1
3534
],
3535
index=stats_index,
3536
name='a'
3537
)
3538
)
3539
pd.testing.assert_series_equal(
3540
logs.stats(column='g1', group_by=group_by),
3541
pd.Series([
3542
pd.Timestamp('2020-01-01 00:00:00'), pd.Timestamp('2020-01-08 00:00:00'),
3543
pd.Timedelta('8 days 00:00:00'), 16, 0, 14, 2, 0, 14, 2
3544
],
3545
index=stats_index,
3546
name='g1'
3547
)
3548
)
3549
pd.testing.assert_series_equal(
3550
logs['c'].stats(),
3551
logs.stats(column='c')
3552
)
3553
pd.testing.assert_series_equal(
3554
logs['c'].stats(),
3555
logs.stats(column='c', group_by=False)
3556
)
3557
pd.testing.assert_series_equal(
3558
logs_grouped['g2'].stats(),
3559
logs_grouped.stats(column='g2')
3560
)
3561
pd.testing.assert_series_equal(
3562
logs_grouped['g2'].stats(),
3563
logs.stats(column='g2', group_by=group_by)
3564
)
3565
stats_df = logs.stats(agg_func=None)
3566
assert stats_df.shape == (4, 10)
3567
pd.testing.assert_index_equal(stats_df.index, logs.wrapper.columns)
3568
pd.testing.assert_index_equal(stats_df.columns, stats_index)
3569
3570
def test_count(self):
3571
assert logs['a'].count() == 8
3572
pd.testing.assert_series_equal(
3573
logs.count(),
3574
pd.Series(
3575
np.array([8, 8, 8, 8]),
3576
index=pd.Index(['a', 'b', 'c', 'd'], dtype='object')
3577
).rename('count')
3578
)
3579
pd.testing.assert_series_equal(
3580
logs_grouped.count(),
3581
pd.Series(
3582
np.array([16, 16]),
3583
index=pd.Index(['g1', 'g2'], dtype='object')
3584
).rename('count')
3585
)
3586
3587