tea-bond 0.4.3__cp38-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- pybond/__init__.py +26 -0
- pybond/bond.py +209 -0
- pybond/download.py +145 -0
- pybond/ffi/__init__.py +4 -0
- pybond/ffi/bond.py +68 -0
- pybond/ffi/datetime.py +58 -0
- pybond/ffi/duration.py +19 -0
- pybond/ffi/evaluators.py +186 -0
- pybond/ffi/lib.py +8 -0
- pybond/nb/__init__.py +31 -0
- pybond/nb/ir_utils.py +47 -0
- pybond/nb/nb_bond.py +213 -0
- pybond/nb/nb_date.py +209 -0
- pybond/nb/nb_datetime.py +415 -0
- pybond/nb/nb_duration.py +70 -0
- pybond/nb/nb_evaluators.py +557 -0
- pybond/nb/nb_time.py +279 -0
- pybond/pd.py +474 -0
- pybond/pl.py +533 -0
- pybond/pnl.py +280 -0
- pybond/polars_utils.py +98 -0
- pybond/pybond.abi3.so +0 -0
- pybond/pybond.pyi +390 -0
- pybond.libs/libcom_err-2abe824b.so.2 +0 -0
- pybond.libs/libcrypto-d3570994.so.10 +0 -0
- pybond.libs/libgssapi_krb5-497db0c6.so.2 +0 -0
- pybond.libs/libk5crypto-b1f99d5c.so.3 +0 -0
- pybond.libs/libkeyutils-dfe70bd6.so.1 +0 -0
- pybond.libs/libkrb5-fcafa220.so.3 +0 -0
- pybond.libs/libkrb5support-d0bcff84.so.0 +0 -0
- pybond.libs/libpcre-9513aab5.so.1 +0 -0
- pybond.libs/libselinux-0922c95c.so.1 +0 -0
- pybond.libs/libssl-cd1d6220.so.10 +0 -0
- tea_bond-0.4.3.dist-info/METADATA +7 -0
- tea_bond-0.4.3.dist-info/RECORD +36 -0
- tea_bond-0.4.3.dist-info/WHEEL +5 -0
pybond/ffi/evaluators.py
ADDED
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
import ctypes
|
|
2
|
+
|
|
3
|
+
from .lib import lib
|
|
4
|
+
|
|
5
|
+
# TfEvaluator creation and destruction
|
|
6
|
+
create_tf_evaluator = lib.create_tf_evaluator
|
|
7
|
+
create_tf_evaluator.argtypes = [
|
|
8
|
+
ctypes.c_void_p, # future_code_ptr
|
|
9
|
+
ctypes.c_size_t, # future_code_len
|
|
10
|
+
ctypes.c_double, # future_price
|
|
11
|
+
ctypes.c_void_p, # bond_code_ptr
|
|
12
|
+
ctypes.c_size_t, # bond_code_len
|
|
13
|
+
ctypes.c_double, # bond_ytm
|
|
14
|
+
ctypes.c_double, # capital_rate
|
|
15
|
+
ctypes.c_uint32, # year
|
|
16
|
+
ctypes.c_uint32, # month
|
|
17
|
+
ctypes.c_uint32, # day
|
|
18
|
+
]
|
|
19
|
+
create_tf_evaluator.restype = ctypes.c_void_p
|
|
20
|
+
|
|
21
|
+
create_tf_evaluator_with_reinvest = lib.create_tf_evaluator_with_reinvest
|
|
22
|
+
create_tf_evaluator_with_reinvest.argtypes = [
|
|
23
|
+
ctypes.c_void_p, # future_code_ptr
|
|
24
|
+
ctypes.c_size_t, # future_code_len
|
|
25
|
+
ctypes.c_double, # future_price
|
|
26
|
+
ctypes.c_void_p, # bond_code_ptr
|
|
27
|
+
ctypes.c_size_t, # bond_code_len
|
|
28
|
+
ctypes.c_double, # bond_ytm
|
|
29
|
+
ctypes.c_double, # capital_rate
|
|
30
|
+
ctypes.c_double, # reinvest_rate
|
|
31
|
+
ctypes.c_uint32, # year
|
|
32
|
+
ctypes.c_uint32, # month
|
|
33
|
+
ctypes.c_uint32, # day
|
|
34
|
+
]
|
|
35
|
+
create_tf_evaluator_with_reinvest.restype = ctypes.c_void_p
|
|
36
|
+
|
|
37
|
+
free_tf_evaluator = lib.free_tf_evaluator
|
|
38
|
+
free_tf_evaluator.argtypes = [ctypes.c_void_p]
|
|
39
|
+
free_tf_evaluator.restype = None
|
|
40
|
+
|
|
41
|
+
# Basic properties
|
|
42
|
+
tf_evaluator_is_deliverable = lib.tf_evaluator_is_deliverable
|
|
43
|
+
tf_evaluator_is_deliverable.argtypes = [ctypes.c_void_p]
|
|
44
|
+
tf_evaluator_is_deliverable.restype = ctypes.c_int
|
|
45
|
+
|
|
46
|
+
tf_evaluator_bond_code = lib.tf_evaluator_bond_code
|
|
47
|
+
tf_evaluator_bond_code.argtypes = [ctypes.c_void_p]
|
|
48
|
+
tf_evaluator_bond_code.restype = ctypes.c_char_p
|
|
49
|
+
|
|
50
|
+
tf_evaluator_future_code = lib.tf_evaluator_future_code
|
|
51
|
+
tf_evaluator_future_code.argtypes = [ctypes.c_void_p]
|
|
52
|
+
tf_evaluator_future_code.restype = ctypes.c_char_p
|
|
53
|
+
|
|
54
|
+
tf_evaluator_bond_ytm = lib.tf_evaluator_bond_ytm
|
|
55
|
+
tf_evaluator_bond_ytm.argtypes = [ctypes.c_void_p]
|
|
56
|
+
tf_evaluator_bond_ytm.restype = ctypes.c_double
|
|
57
|
+
|
|
58
|
+
tf_evaluator_future_price = lib.tf_evaluator_future_price
|
|
59
|
+
tf_evaluator_future_price.argtypes = [ctypes.c_void_p]
|
|
60
|
+
tf_evaluator_future_price.restype = ctypes.c_double
|
|
61
|
+
|
|
62
|
+
tf_evaluator_capital_rate = lib.tf_evaluator_capital_rate
|
|
63
|
+
tf_evaluator_capital_rate.argtypes = [ctypes.c_void_p]
|
|
64
|
+
tf_evaluator_capital_rate.restype = ctypes.c_double
|
|
65
|
+
|
|
66
|
+
tf_evaluator_reinvest_rate = lib.tf_evaluator_reinvest_rate
|
|
67
|
+
tf_evaluator_reinvest_rate.argtypes = [ctypes.c_void_p]
|
|
68
|
+
tf_evaluator_reinvest_rate.restype = ctypes.c_double
|
|
69
|
+
|
|
70
|
+
# Date functions
|
|
71
|
+
tf_evaluator_get_date = lib.tf_evaluator_get_date
|
|
72
|
+
tf_evaluator_get_date.argtypes = [
|
|
73
|
+
ctypes.c_void_p,
|
|
74
|
+
ctypes.POINTER(ctypes.c_uint32),
|
|
75
|
+
ctypes.POINTER(ctypes.c_uint32),
|
|
76
|
+
ctypes.POINTER(ctypes.c_uint32),
|
|
77
|
+
]
|
|
78
|
+
tf_evaluator_get_date.restype = None
|
|
79
|
+
|
|
80
|
+
tf_evaluator_get_deliver_date = lib.tf_evaluator_get_deliver_date
|
|
81
|
+
tf_evaluator_get_deliver_date.argtypes = [
|
|
82
|
+
ctypes.c_void_p,
|
|
83
|
+
ctypes.POINTER(ctypes.c_uint32),
|
|
84
|
+
ctypes.POINTER(ctypes.c_uint32),
|
|
85
|
+
ctypes.POINTER(ctypes.c_uint32),
|
|
86
|
+
]
|
|
87
|
+
tf_evaluator_get_deliver_date.restype = ctypes.c_int
|
|
88
|
+
|
|
89
|
+
# Calculation functions
|
|
90
|
+
tf_evaluator_accrued_interest = lib.tf_evaluator_accrued_interest
|
|
91
|
+
tf_evaluator_accrued_interest.argtypes = [ctypes.c_void_p]
|
|
92
|
+
tf_evaluator_accrued_interest.restype = ctypes.c_double
|
|
93
|
+
|
|
94
|
+
tf_evaluator_deliver_accrued_interest = lib.tf_evaluator_deliver_accrued_interest
|
|
95
|
+
tf_evaluator_deliver_accrued_interest.argtypes = [ctypes.c_void_p]
|
|
96
|
+
tf_evaluator_deliver_accrued_interest.restype = ctypes.c_double
|
|
97
|
+
|
|
98
|
+
tf_evaluator_cf = lib.tf_evaluator_cf
|
|
99
|
+
tf_evaluator_cf.argtypes = [ctypes.c_void_p]
|
|
100
|
+
tf_evaluator_cf.restype = ctypes.c_double
|
|
101
|
+
|
|
102
|
+
tf_evaluator_dirty_price = lib.tf_evaluator_dirty_price
|
|
103
|
+
tf_evaluator_dirty_price.argtypes = [ctypes.c_void_p]
|
|
104
|
+
tf_evaluator_dirty_price.restype = ctypes.c_double
|
|
105
|
+
|
|
106
|
+
tf_evaluator_clean_price = lib.tf_evaluator_clean_price
|
|
107
|
+
tf_evaluator_clean_price.argtypes = [ctypes.c_void_p]
|
|
108
|
+
tf_evaluator_clean_price.restype = ctypes.c_double
|
|
109
|
+
|
|
110
|
+
tf_evaluator_future_dirty_price = lib.tf_evaluator_future_dirty_price
|
|
111
|
+
tf_evaluator_future_dirty_price.argtypes = [ctypes.c_void_p]
|
|
112
|
+
tf_evaluator_future_dirty_price.restype = ctypes.c_double
|
|
113
|
+
|
|
114
|
+
tf_evaluator_deliver_cost = lib.tf_evaluator_deliver_cost
|
|
115
|
+
tf_evaluator_deliver_cost.argtypes = [ctypes.c_void_p]
|
|
116
|
+
tf_evaluator_deliver_cost.restype = ctypes.c_double
|
|
117
|
+
|
|
118
|
+
tf_evaluator_basis_spread = lib.tf_evaluator_basis_spread
|
|
119
|
+
tf_evaluator_basis_spread.argtypes = [ctypes.c_void_p]
|
|
120
|
+
tf_evaluator_basis_spread.restype = ctypes.c_double
|
|
121
|
+
|
|
122
|
+
tf_evaluator_f_b_spread = lib.tf_evaluator_f_b_spread
|
|
123
|
+
tf_evaluator_f_b_spread.argtypes = [ctypes.c_void_p]
|
|
124
|
+
tf_evaluator_f_b_spread.restype = ctypes.c_double
|
|
125
|
+
|
|
126
|
+
tf_evaluator_carry = lib.tf_evaluator_carry
|
|
127
|
+
tf_evaluator_carry.argtypes = [ctypes.c_void_p]
|
|
128
|
+
tf_evaluator_carry.restype = ctypes.c_double
|
|
129
|
+
|
|
130
|
+
tf_evaluator_net_basis_spread = lib.tf_evaluator_net_basis_spread
|
|
131
|
+
tf_evaluator_net_basis_spread.argtypes = [ctypes.c_void_p]
|
|
132
|
+
tf_evaluator_net_basis_spread.restype = ctypes.c_double
|
|
133
|
+
|
|
134
|
+
tf_evaluator_duration = lib.tf_evaluator_duration
|
|
135
|
+
tf_evaluator_duration.argtypes = [ctypes.c_void_p]
|
|
136
|
+
tf_evaluator_duration.restype = ctypes.c_double
|
|
137
|
+
|
|
138
|
+
tf_evaluator_irr = lib.tf_evaluator_irr
|
|
139
|
+
tf_evaluator_irr.argtypes = [ctypes.c_void_p]
|
|
140
|
+
tf_evaluator_irr.restype = ctypes.c_double
|
|
141
|
+
|
|
142
|
+
tf_evaluator_future_ytm = lib.tf_evaluator_future_ytm
|
|
143
|
+
tf_evaluator_future_ytm.argtypes = [ctypes.c_void_p]
|
|
144
|
+
tf_evaluator_future_ytm.restype = ctypes.c_double
|
|
145
|
+
|
|
146
|
+
tf_evaluator_remain_days_to_deliver = lib.tf_evaluator_remain_days_to_deliver
|
|
147
|
+
tf_evaluator_remain_days_to_deliver.argtypes = [ctypes.c_void_p]
|
|
148
|
+
tf_evaluator_remain_days_to_deliver.restype = ctypes.c_int
|
|
149
|
+
|
|
150
|
+
tf_evaluator_remain_cp_num = lib.tf_evaluator_remain_cp_num
|
|
151
|
+
tf_evaluator_remain_cp_num.argtypes = [ctypes.c_void_p]
|
|
152
|
+
tf_evaluator_remain_cp_num.restype = ctypes.c_int
|
|
153
|
+
|
|
154
|
+
tf_evaluator_remain_cp_to_deliver = lib.tf_evaluator_remain_cp_to_deliver
|
|
155
|
+
tf_evaluator_remain_cp_to_deliver.argtypes = [ctypes.c_void_p]
|
|
156
|
+
tf_evaluator_remain_cp_to_deliver.restype = ctypes.c_double
|
|
157
|
+
|
|
158
|
+
tf_evaluator_remain_cp_to_deliver_wm = lib.tf_evaluator_remain_cp_to_deliver_wm
|
|
159
|
+
tf_evaluator_remain_cp_to_deliver_wm.argtypes = [ctypes.c_void_p]
|
|
160
|
+
tf_evaluator_remain_cp_to_deliver_wm.restype = ctypes.c_double
|
|
161
|
+
|
|
162
|
+
tf_evaluator_calc_all = lib.tf_evaluator_calc_all
|
|
163
|
+
tf_evaluator_calc_all.argtypes = [ctypes.c_void_p]
|
|
164
|
+
tf_evaluator_calc_all.restype = ctypes.c_int
|
|
165
|
+
|
|
166
|
+
# Update function
|
|
167
|
+
tf_evaluator_update_info = lib.tf_evaluator_update_info
|
|
168
|
+
tf_evaluator_update_info.argtypes = [
|
|
169
|
+
ctypes.c_void_p, # evaluator
|
|
170
|
+
ctypes.c_void_p, # future_code_ptr
|
|
171
|
+
ctypes.c_size_t, # future_code_len
|
|
172
|
+
ctypes.c_double, # future_price
|
|
173
|
+
ctypes.c_void_p, # bond_code_ptr
|
|
174
|
+
ctypes.c_size_t, # bond_code_len
|
|
175
|
+
ctypes.c_double, # bond_ytm
|
|
176
|
+
ctypes.c_double, # capital_rate
|
|
177
|
+
ctypes.c_uint32, # year
|
|
178
|
+
ctypes.c_uint32, # month
|
|
179
|
+
ctypes.c_uint32, # day
|
|
180
|
+
]
|
|
181
|
+
tf_evaluator_update_info.restype = ctypes.c_int
|
|
182
|
+
|
|
183
|
+
# Utility function
|
|
184
|
+
free_string = lib.free_string
|
|
185
|
+
free_string.argtypes = [ctypes.c_char_p]
|
|
186
|
+
free_string.restype = None
|
pybond/ffi/lib.py
ADDED
pybond/nb/__init__.py
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# from datetime import date, datetime, time
|
|
2
|
+
|
|
3
|
+
from .nb_bond import Bond, BondType, bond_type
|
|
4
|
+
from .nb_date import DateType, date_type
|
|
5
|
+
from .nb_datetime import DateTime, DateTimeType, datetime_type
|
|
6
|
+
from .nb_duration import Duration, DurationType, duration_type
|
|
7
|
+
from .nb_evaluators import TfEvaluator, TfEvaluatorType, tf_evaluator_type
|
|
8
|
+
from .nb_time import Time, TimeType, time_type
|
|
9
|
+
|
|
10
|
+
__all__ = [
|
|
11
|
+
"Bond",
|
|
12
|
+
"BondType",
|
|
13
|
+
"DateTime",
|
|
14
|
+
"DateTimeType",
|
|
15
|
+
"DateType",
|
|
16
|
+
"Duration",
|
|
17
|
+
"DurationType",
|
|
18
|
+
"TfEvaluator",
|
|
19
|
+
"TfEvaluatorType",
|
|
20
|
+
"Time",
|
|
21
|
+
"TimeType",
|
|
22
|
+
"bond_type",
|
|
23
|
+
# "date",
|
|
24
|
+
"date_type",
|
|
25
|
+
# "datetime",
|
|
26
|
+
"datetime_type",
|
|
27
|
+
"duration_type",
|
|
28
|
+
"tf_evaluator_type",
|
|
29
|
+
# "time",
|
|
30
|
+
"time_type",
|
|
31
|
+
]
|
pybond/nb/ir_utils.py
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
from llvmlite import ir
|
|
2
|
+
from numba.core import cgutils
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
def ir_isinstance(pyapi, obj, typ):
|
|
6
|
+
fnty = ir.FunctionType(ir.IntType(1), [pyapi.pyobj, pyapi.pyobj])
|
|
7
|
+
fn = cgutils.get_or_insert_function(
|
|
8
|
+
pyapi.builder.module, fnty, name="PyObject_IsInstance"
|
|
9
|
+
)
|
|
10
|
+
return pyapi.builder.call(fn, (obj, typ))
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def ir_build_datetime(val, builder, *, from_utc: bool = False):
|
|
14
|
+
mod = builder.module
|
|
15
|
+
fnty = ir.FunctionType(ir.PointerType(ir.IntType(8)), [ir.IntType(64)])
|
|
16
|
+
if not from_utc:
|
|
17
|
+
build_datetime_ns_fn = cgutils.get_or_insert_function(
|
|
18
|
+
mod, fnty, "build_datetime_ns"
|
|
19
|
+
)
|
|
20
|
+
else:
|
|
21
|
+
build_datetime_ns_fn = cgutils.get_or_insert_function(
|
|
22
|
+
mod, fnty, "build_datetime_from_utc_ns"
|
|
23
|
+
)
|
|
24
|
+
ptr = builder.call(build_datetime_ns_fn, [val])
|
|
25
|
+
return ptr
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def ir_timestamp_nanos(ptr, builder):
|
|
29
|
+
mod = builder.module
|
|
30
|
+
fnty = ir.FunctionType(ir.IntType(64), [ir.PointerType(ir.IntType(8))])
|
|
31
|
+
fn = cgutils.get_or_insert_function(mod, fnty, "timestamp_nanos")
|
|
32
|
+
ptr = builder.call(fn, [ptr])
|
|
33
|
+
return ptr
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def ir_local_timestamp_nanos(ptr, builder):
|
|
37
|
+
mod = builder.module
|
|
38
|
+
fnty = ir.FunctionType(ir.IntType(64), [ir.PointerType(ir.IntType(8))])
|
|
39
|
+
fn = cgutils.get_or_insert_function(mod, fnty, "local_timestamp_nanos")
|
|
40
|
+
ptr = builder.call(fn, [ptr])
|
|
41
|
+
return ptr
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
def long_as_ulong(pyapi, numobj):
|
|
45
|
+
fnty = ir.FunctionType(pyapi.ulong, [pyapi.pyobj])
|
|
46
|
+
fn = pyapi._get_function(fnty, name="PyLong_AsUnsignedLong")
|
|
47
|
+
return pyapi.builder.call(fn, [numobj])
|
pybond/nb/nb_bond.py
ADDED
|
@@ -0,0 +1,213 @@
|
|
|
1
|
+
from llvmlite import ir
|
|
2
|
+
from numba import types
|
|
3
|
+
from numba.core import cgutils, utils
|
|
4
|
+
from numba.cpython.hashing import _Py_hash_t
|
|
5
|
+
from numba.extending import (
|
|
6
|
+
as_numba_type,
|
|
7
|
+
box,
|
|
8
|
+
intrinsic,
|
|
9
|
+
lower_builtin,
|
|
10
|
+
make_attribute_wrapper,
|
|
11
|
+
models,
|
|
12
|
+
overload_attribute,
|
|
13
|
+
overload_method,
|
|
14
|
+
register_model,
|
|
15
|
+
type_callable,
|
|
16
|
+
typeof_impl,
|
|
17
|
+
)
|
|
18
|
+
|
|
19
|
+
from pybond import Bond
|
|
20
|
+
from pybond.ffi import (
|
|
21
|
+
bond_accrued_interest,
|
|
22
|
+
bond_calc_ytm,
|
|
23
|
+
bond_clean_price,
|
|
24
|
+
bond_coupon_rate,
|
|
25
|
+
bond_dirty_price,
|
|
26
|
+
bond_duration,
|
|
27
|
+
)
|
|
28
|
+
from pybond.nb.nb_datetime import DateTimeType # , create_bond
|
|
29
|
+
|
|
30
|
+
from .nb_date import DateType
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
class BondType(types.Type):
|
|
34
|
+
def __init__(self):
|
|
35
|
+
super().__init__(name="Bond")
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
bond_type = BondType()
|
|
39
|
+
as_numba_type.register(Bond, bond_type)
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
@typeof_impl.register(Bond)
|
|
43
|
+
def typeof_bond(val, c):
|
|
44
|
+
return bond_type
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
@type_callable(Bond)
|
|
48
|
+
def type_bond(context):
|
|
49
|
+
def typer(val):
|
|
50
|
+
return bond_type
|
|
51
|
+
|
|
52
|
+
return typer
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
@register_model(BondType)
|
|
56
|
+
class BondModel(models.StructModel):
|
|
57
|
+
def __init__(self, dmm, fe_type):
|
|
58
|
+
members = [
|
|
59
|
+
("ptr", types.voidptr),
|
|
60
|
+
]
|
|
61
|
+
models.StructModel.__init__(self, dmm, fe_type, members)
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
make_attribute_wrapper(BondType, "ptr", "ptr")
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
@lower_builtin(Bond, types.string)
|
|
68
|
+
def impl_bond_builder(context, builder, sig, args):
|
|
69
|
+
typ = sig.return_type
|
|
70
|
+
(val,) = args
|
|
71
|
+
# Get string data from Numba string
|
|
72
|
+
code = context.make_helper(builder, types.string, val)
|
|
73
|
+
fn = cgutils.get_or_insert_function(
|
|
74
|
+
builder.module,
|
|
75
|
+
ir.FunctionType(
|
|
76
|
+
ir.PointerType(ir.IntType(8)),
|
|
77
|
+
[ir.PointerType(ir.IntType(8)), ir.IntType(utils.MACHINE_BITS)],
|
|
78
|
+
),
|
|
79
|
+
name="create_bond",
|
|
80
|
+
)
|
|
81
|
+
ptr = builder.call(fn, [code.data, code.length])
|
|
82
|
+
# Create Bond object
|
|
83
|
+
bond = cgutils.create_struct_proxy(typ)(context, builder)
|
|
84
|
+
bond.ptr = ptr
|
|
85
|
+
return bond._getvalue()
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
@overload_attribute(BondType, "coupon_rate")
|
|
89
|
+
def bond_attr_coupon_rate(bond):
|
|
90
|
+
def impl(bond):
|
|
91
|
+
return bond_coupon_rate(bond.ptr)
|
|
92
|
+
|
|
93
|
+
return impl
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
def ir_get_bond_full_code(ptr, context, builder):
|
|
97
|
+
"""根据Bond的指针获取bond的代码(包括交易所信息)"""
|
|
98
|
+
fn = cgutils.get_or_insert_function(
|
|
99
|
+
builder.module,
|
|
100
|
+
ir.FunctionType(ir.PointerType(ir.IntType(8)), [ir.PointerType(ir.IntType(8))]),
|
|
101
|
+
name="bond_full_code",
|
|
102
|
+
)
|
|
103
|
+
cstr = builder.call(fn, [ptr])
|
|
104
|
+
# 使用 LLVM strlen
|
|
105
|
+
strlen_fn = cgutils.get_or_insert_function(
|
|
106
|
+
builder.module,
|
|
107
|
+
ir.FunctionType(ir.IntType(64), [ir.PointerType(ir.IntType(8))]),
|
|
108
|
+
name="strlen",
|
|
109
|
+
)
|
|
110
|
+
length = builder.call(strlen_fn, [cstr])
|
|
111
|
+
uni_str = cgutils.create_struct_proxy(types.unicode_type)(context, builder)
|
|
112
|
+
uni_str.data = cstr
|
|
113
|
+
uni_str.length = length
|
|
114
|
+
uni_str.kind = ir.Constant(ir.IntType(32), 1) # kind=1 is PY_UNICODE_1BYTE_KIND
|
|
115
|
+
uni_str.is_ascii = ir.Constant(ir.IntType(32), 1)
|
|
116
|
+
uni_str.meminfo = context.get_constant_null(types.voidptr)
|
|
117
|
+
# Set hash to -1 to indicate that it should be computed.
|
|
118
|
+
# We cannot bake in the hash value because of hashseed randomization.
|
|
119
|
+
uni_str.hash = context.get_constant(_Py_hash_t, -1)
|
|
120
|
+
uni_str.parent = cgutils.get_null_value(uni_str.parent.type)
|
|
121
|
+
return uni_str._getvalue()
|
|
122
|
+
|
|
123
|
+
|
|
124
|
+
@intrinsic
|
|
125
|
+
def get_bond_full_code(typingctx, bond_ptr):
|
|
126
|
+
"""根据Bond的指针获取bond的代码(包括交易所信息)"""
|
|
127
|
+
|
|
128
|
+
def codegen(context, builder, sig, args):
|
|
129
|
+
return ir_get_bond_full_code(args[0], context, builder)
|
|
130
|
+
|
|
131
|
+
sig = types.unicode_type(bond_ptr)
|
|
132
|
+
return sig, codegen
|
|
133
|
+
|
|
134
|
+
|
|
135
|
+
@overload_attribute(BondType, "full_code")
|
|
136
|
+
def get_full_code_attr(bond):
|
|
137
|
+
if isinstance(bond, BondType):
|
|
138
|
+
|
|
139
|
+
def impl(bond):
|
|
140
|
+
return get_bond_full_code(bond.ptr)
|
|
141
|
+
|
|
142
|
+
return impl
|
|
143
|
+
|
|
144
|
+
|
|
145
|
+
@overload_method(BondType, "duration")
|
|
146
|
+
def bond_calc_duration(bond, ytm, date):
|
|
147
|
+
if not isinstance(date, (DateType, DateTimeType)):
|
|
148
|
+
return
|
|
149
|
+
|
|
150
|
+
def impl(bond, ytm, date):
|
|
151
|
+
return bond_duration(bond.ptr, ytm, date.year, date.month, date.day)
|
|
152
|
+
|
|
153
|
+
return impl
|
|
154
|
+
|
|
155
|
+
|
|
156
|
+
@overload_method(BondType, "accrued_interest")
|
|
157
|
+
def bond_calc_accrued_interest(bond, date):
|
|
158
|
+
if not isinstance(date, (DateType, DateTimeType)):
|
|
159
|
+
return
|
|
160
|
+
|
|
161
|
+
def impl(bond, date):
|
|
162
|
+
return bond_accrued_interest(bond.ptr, date.year, date.month, date.day)
|
|
163
|
+
|
|
164
|
+
return impl
|
|
165
|
+
|
|
166
|
+
|
|
167
|
+
@overload_method(BondType, "dirty_price")
|
|
168
|
+
def bond_calc_dirty_price(bond, ytm, date):
|
|
169
|
+
if not isinstance(date, (DateType, DateTimeType)):
|
|
170
|
+
return
|
|
171
|
+
|
|
172
|
+
def impl(bond, ytm, date):
|
|
173
|
+
return bond_dirty_price(bond.ptr, ytm, date.year, date.month, date.day)
|
|
174
|
+
|
|
175
|
+
return impl
|
|
176
|
+
|
|
177
|
+
|
|
178
|
+
@overload_method(BondType, "clean_price")
|
|
179
|
+
def bond_calc_clean_price(bond, ytm, date):
|
|
180
|
+
if not isinstance(date, (DateType, DateTimeType)):
|
|
181
|
+
return
|
|
182
|
+
|
|
183
|
+
def impl(bond, ytm, date):
|
|
184
|
+
return bond_clean_price(bond.ptr, ytm, date.year, date.month, date.day)
|
|
185
|
+
|
|
186
|
+
return impl
|
|
187
|
+
|
|
188
|
+
|
|
189
|
+
@overload_method(BondType, "calc_ytm_with_price")
|
|
190
|
+
def bond_ytm_with_price(bond, dirty_price, date):
|
|
191
|
+
if not isinstance(date, (DateType, DateTimeType)):
|
|
192
|
+
return
|
|
193
|
+
|
|
194
|
+
def impl(bond, dirty_price, date):
|
|
195
|
+
return bond_calc_ytm(bond.ptr, dirty_price, date.year, date.month, date.day)
|
|
196
|
+
|
|
197
|
+
return impl
|
|
198
|
+
|
|
199
|
+
|
|
200
|
+
@box(BondType)
|
|
201
|
+
def box_bond(typ, val, c):
|
|
202
|
+
"""
|
|
203
|
+
Convert a native Bond structure to python Bond.
|
|
204
|
+
"""
|
|
205
|
+
bond = cgutils.create_struct_proxy(typ)(c.context, c.builder, value=val)
|
|
206
|
+
bond_code = ir_get_bond_full_code(bond.ptr, c.context, c.builder)
|
|
207
|
+
# Call Bond new to create a new Bond object
|
|
208
|
+
val_obj = c.pyapi.from_native_value(types.unicode_type, bond_code)
|
|
209
|
+
class_obj = c.pyapi.unserialize(c.pyapi.serialize_object(Bond))
|
|
210
|
+
res = c.pyapi.call_function_objargs(class_obj, (val_obj,))
|
|
211
|
+
c.pyapi.decref(val_obj)
|
|
212
|
+
c.pyapi.decref(class_obj)
|
|
213
|
+
return res
|
pybond/nb/nb_date.py
ADDED
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
import datetime
|
|
2
|
+
import operator
|
|
3
|
+
|
|
4
|
+
from llvmlite import ir
|
|
5
|
+
from numba import types
|
|
6
|
+
from numba.core import cgutils
|
|
7
|
+
from numba.extending import (
|
|
8
|
+
NativeValue,
|
|
9
|
+
as_numba_type,
|
|
10
|
+
box,
|
|
11
|
+
lower_builtin,
|
|
12
|
+
make_attribute_wrapper,
|
|
13
|
+
models,
|
|
14
|
+
overload,
|
|
15
|
+
register_model,
|
|
16
|
+
type_callable,
|
|
17
|
+
typeof_impl,
|
|
18
|
+
unbox,
|
|
19
|
+
)
|
|
20
|
+
|
|
21
|
+
from .ir_utils import long_as_ulong
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
class DateType(types.Type):
|
|
25
|
+
def __init__(self):
|
|
26
|
+
super().__init__(name="Date")
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
date_type = DateType()
|
|
30
|
+
as_numba_type.register(datetime.date, date_type)
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
@typeof_impl.register(datetime.date)
|
|
34
|
+
def typeof_datetime_date(val, c):
|
|
35
|
+
return date_type
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
@type_callable(datetime.date)
|
|
39
|
+
def type_date(context):
|
|
40
|
+
def typer(year, month, day):
|
|
41
|
+
return date_type
|
|
42
|
+
|
|
43
|
+
return typer
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
@register_model(DateType)
|
|
47
|
+
class DateModel(models.StructModel):
|
|
48
|
+
def __init__(self, dmm, fe_type):
|
|
49
|
+
members = [
|
|
50
|
+
("year", types.uint32),
|
|
51
|
+
("month", types.uint32),
|
|
52
|
+
("day", types.uint32),
|
|
53
|
+
]
|
|
54
|
+
models.StructModel.__init__(self, dmm, fe_type, members)
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
make_attribute_wrapper(DateType, "year", "year")
|
|
58
|
+
make_attribute_wrapper(DateType, "month", "month")
|
|
59
|
+
make_attribute_wrapper(DateType, "day", "day")
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
@lower_builtin(datetime.date, types.uint32, types.uint32, types.uint32)
|
|
63
|
+
@lower_builtin(datetime.date, types.int32, types.int32, types.int32)
|
|
64
|
+
def datetime_date_constructor_u32(context, builder, sig, args):
|
|
65
|
+
date_type = sig.return_type
|
|
66
|
+
date = cgutils.create_struct_proxy(date_type)(context, builder)
|
|
67
|
+
date.year = args[0]
|
|
68
|
+
date.month = args[1]
|
|
69
|
+
date.day = args[2]
|
|
70
|
+
return date._getvalue()
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
@lower_builtin(datetime.date, types.int64, types.int64, types.int64)
|
|
74
|
+
def datetime_date_constructor_i64(context, builder, sig, args):
|
|
75
|
+
date_type = sig.return_type
|
|
76
|
+
date = cgutils.create_struct_proxy(date_type)(context, builder)
|
|
77
|
+
date.year = builder.trunc(args[0], ir.IntType(32))
|
|
78
|
+
date.month = builder.trunc(args[1], ir.IntType(32))
|
|
79
|
+
date.day = builder.trunc(args[2], ir.IntType(32))
|
|
80
|
+
return date._getvalue()
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
@unbox(DateType)
|
|
84
|
+
def unbox_date(typ, obj, c):
|
|
85
|
+
year_obj = c.pyapi.object_getattr_string(obj, "year")
|
|
86
|
+
year = long_as_ulong(c.pyapi, year_obj)
|
|
87
|
+
month_obj = c.pyapi.object_getattr_string(obj, "month")
|
|
88
|
+
month = long_as_ulong(c.pyapi, month_obj)
|
|
89
|
+
day_obj = c.pyapi.object_getattr_string(obj, "day")
|
|
90
|
+
second = long_as_ulong(c.pyapi, day_obj)
|
|
91
|
+
c.pyapi.decref(year_obj)
|
|
92
|
+
c.pyapi.decref(month_obj)
|
|
93
|
+
c.pyapi.decref(day_obj)
|
|
94
|
+
|
|
95
|
+
date = cgutils.create_struct_proxy(typ)(c.context, c.builder)
|
|
96
|
+
date.year = c.builder.trunc(year, ir.IntType(32))
|
|
97
|
+
date.month = c.builder.trunc(month, ir.IntType(32))
|
|
98
|
+
date.day = c.builder.trunc(second, ir.IntType(32))
|
|
99
|
+
# Check for errors
|
|
100
|
+
is_error = cgutils.is_not_null(c.builder, c.pyapi.err_occurred())
|
|
101
|
+
return NativeValue(date._getvalue(), is_error=is_error)
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
@box(DateType)
|
|
105
|
+
def box_date(typ, val, c):
|
|
106
|
+
"""
|
|
107
|
+
Box a native date object into a Python datetime.date object.
|
|
108
|
+
"""
|
|
109
|
+
date = cgutils.create_struct_proxy(typ)(c.context, c.builder, value=val)
|
|
110
|
+
year_obj = c.pyapi.long_from_unsigned_int(date.year)
|
|
111
|
+
month_obj = c.pyapi.long_from_unsigned_int(date.month)
|
|
112
|
+
day_obj = c.pyapi.long_from_unsigned_int(date.day)
|
|
113
|
+
|
|
114
|
+
class_obj = c.pyapi.unserialize(c.pyapi.serialize_object(datetime.date))
|
|
115
|
+
date_obj = c.pyapi.call_function_objargs(class_obj, (year_obj, month_obj, day_obj))
|
|
116
|
+
c.pyapi.decref(year_obj)
|
|
117
|
+
c.pyapi.decref(month_obj)
|
|
118
|
+
c.pyapi.decref(day_obj)
|
|
119
|
+
return date_obj
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
@overload(operator.ge)
|
|
123
|
+
def impl_ge(dt, dt2):
|
|
124
|
+
if not isinstance(dt, DateType) or not isinstance(dt, DateType):
|
|
125
|
+
return
|
|
126
|
+
|
|
127
|
+
def impl(dt, dt2):
|
|
128
|
+
if dt.year == dt2.year:
|
|
129
|
+
if dt.month == dt2.month:
|
|
130
|
+
return dt.day >= dt2.day
|
|
131
|
+
else:
|
|
132
|
+
return dt.month >= dt2.month
|
|
133
|
+
else:
|
|
134
|
+
return dt.year >= dt2.year
|
|
135
|
+
|
|
136
|
+
return impl
|
|
137
|
+
|
|
138
|
+
|
|
139
|
+
@overload(operator.gt)
|
|
140
|
+
def impl_gt(dt, dt2):
|
|
141
|
+
if not isinstance(dt, DateType) or not isinstance(dt, DateType):
|
|
142
|
+
return
|
|
143
|
+
|
|
144
|
+
def impl(dt, dt2):
|
|
145
|
+
if dt.year == dt2.year:
|
|
146
|
+
if dt.month == dt2.month:
|
|
147
|
+
return dt.day > dt2.day
|
|
148
|
+
else:
|
|
149
|
+
return dt.month > dt2.month
|
|
150
|
+
else:
|
|
151
|
+
return dt.year > dt2.year
|
|
152
|
+
|
|
153
|
+
return impl
|
|
154
|
+
|
|
155
|
+
|
|
156
|
+
@overload(operator.le)
|
|
157
|
+
def impl_le(dt, dt2):
|
|
158
|
+
if not isinstance(dt, DateType) or not isinstance(dt, DateType):
|
|
159
|
+
return
|
|
160
|
+
|
|
161
|
+
def impl(dt, dt2):
|
|
162
|
+
if dt.year == dt2.year:
|
|
163
|
+
if dt.month == dt2.month:
|
|
164
|
+
return dt.day <= dt2.day
|
|
165
|
+
else:
|
|
166
|
+
return dt.month <= dt2.month
|
|
167
|
+
else:
|
|
168
|
+
return dt.year <= dt2.year
|
|
169
|
+
|
|
170
|
+
return impl
|
|
171
|
+
|
|
172
|
+
|
|
173
|
+
@overload(operator.lt)
|
|
174
|
+
def impl_lt(dt, dt2):
|
|
175
|
+
if not isinstance(dt, DateType) or not isinstance(dt, DateType):
|
|
176
|
+
return
|
|
177
|
+
|
|
178
|
+
def impl(dt, dt2):
|
|
179
|
+
if dt.year == dt2.year:
|
|
180
|
+
if dt.month == dt2.month:
|
|
181
|
+
return dt.day < dt2.day
|
|
182
|
+
else:
|
|
183
|
+
return dt.month < dt2.month
|
|
184
|
+
else:
|
|
185
|
+
return dt.year < dt2.year
|
|
186
|
+
|
|
187
|
+
return impl
|
|
188
|
+
|
|
189
|
+
|
|
190
|
+
@overload(operator.eq)
|
|
191
|
+
def impl_eq(dt, dt2):
|
|
192
|
+
if not isinstance(dt, DateType) or not isinstance(dt, DateType):
|
|
193
|
+
return
|
|
194
|
+
|
|
195
|
+
def impl(dt, dt2):
|
|
196
|
+
return dt.year == dt2.year and dt.month == dt2.month and dt.day == dt2.day
|
|
197
|
+
|
|
198
|
+
return impl
|
|
199
|
+
|
|
200
|
+
|
|
201
|
+
@overload(operator.ne)
|
|
202
|
+
def impl_ne(dt, dt2):
|
|
203
|
+
if not isinstance(dt, DateType) or not isinstance(dt, DateType):
|
|
204
|
+
return
|
|
205
|
+
|
|
206
|
+
def impl(dt, dt2):
|
|
207
|
+
return dt.year != dt2.year or dt.month != dt2.month or dt.day != dt2.day
|
|
208
|
+
|
|
209
|
+
return impl
|