tea-bond 0.3.11__cp38-abi3-manylinux_2_28_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.

Potentially problematic release.


This version of tea-bond might be problematic. Click here for more details.

pybond/ffi/lib.py ADDED
@@ -0,0 +1,8 @@
1
+ import ctypes
2
+
3
+ import llvmlite.binding
4
+
5
+ from pybond import pybond
6
+
7
+ lib = ctypes.cdll.LoadLibrary(pybond.__file__)
8
+ llvmlite.binding.load_library_permanently(pybond.__file__)
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
+ "bond_type",
14
+ "DateTime",
15
+ "DateTimeType",
16
+ "DateType",
17
+ "Duration",
18
+ "DurationType",
19
+ "duration_type",
20
+ "TfEvaluator",
21
+ "TfEvaluatorType",
22
+ "tf_evaluator_type",
23
+ "Time",
24
+ "TimeType",
25
+ # "date",
26
+ "date_type",
27
+ # "datetime",
28
+ "datetime_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