onetick-py 1.173.0__tar.gz → 1.175.0__tar.gz

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.
Files changed (160) hide show
  1. {onetick_py-1.173.0/src/onetick_py.egg-info → onetick_py-1.175.0}/PKG-INFO +2 -2
  2. {onetick_py-1.173.0 → onetick_py-1.175.0}/requirements.strict.txt +1 -1
  3. {onetick_py-1.173.0 → onetick_py-1.175.0}/src/onetick/py/_version.py +1 -1
  4. {onetick_py-1.173.0 → onetick_py-1.175.0}/src/onetick/py/aggregations/_base.py +1 -1
  5. {onetick_py-1.173.0 → onetick_py-1.175.0}/src/onetick/py/aggregations/order_book.py +13 -7
  6. {onetick_py-1.173.0 → onetick_py-1.175.0}/src/onetick/py/aggregations/other.py +2 -2
  7. {onetick_py-1.173.0 → onetick_py-1.175.0}/src/onetick/py/core/_source/source_methods/misc.py +59 -13
  8. {onetick_py-1.173.0 → onetick_py-1.175.0}/src/onetick/py/core/column_operations/_methods/conversions.py +3 -2
  9. {onetick_py-1.173.0 → onetick_py-1.175.0}/src/onetick/py/core/column_operations/_methods/op_types.py +12 -3
  10. {onetick_py-1.173.0 → onetick_py-1.175.0}/src/onetick/py/core/column_operations/base.py +2 -2
  11. {onetick_py-1.173.0 → onetick_py-1.175.0}/src/onetick/py/core/source.py +9 -1
  12. {onetick_py-1.173.0 → onetick_py-1.175.0}/src/onetick/py/functions.py +3 -2
  13. {onetick_py-1.173.0 → onetick_py-1.175.0}/src/onetick/py/types.py +115 -40
  14. {onetick_py-1.173.0 → onetick_py-1.175.0}/src/onetick/py/utils/render.py +271 -58
  15. {onetick_py-1.173.0 → onetick_py-1.175.0}/src/onetick/py/utils/types.py +2 -0
  16. {onetick_py-1.173.0 → onetick_py-1.175.0/src/onetick_py.egg-info}/PKG-INFO +2 -2
  17. {onetick_py-1.173.0 → onetick_py-1.175.0}/src/onetick_py.egg-info/requires.txt +1 -1
  18. {onetick_py-1.173.0 → onetick_py-1.175.0}/LICENSE +0 -0
  19. {onetick_py-1.173.0 → onetick_py-1.175.0}/README.md +0 -0
  20. {onetick_py-1.173.0 → onetick_py-1.175.0}/pyproject.toml +0 -0
  21. {onetick_py-1.173.0 → onetick_py-1.175.0}/requirements.txt +0 -0
  22. {onetick_py-1.173.0 → onetick_py-1.175.0}/setup.cfg +0 -0
  23. {onetick_py-1.173.0 → onetick_py-1.175.0}/setup.py +0 -0
  24. {onetick_py-1.173.0 → onetick_py-1.175.0}/src/locator_parser/__init__.py +0 -0
  25. {onetick_py-1.173.0 → onetick_py-1.175.0}/src/locator_parser/acl.py +0 -0
  26. {onetick_py-1.173.0 → onetick_py-1.175.0}/src/locator_parser/actions.py +0 -0
  27. {onetick_py-1.173.0 → onetick_py-1.175.0}/src/locator_parser/common.py +0 -0
  28. {onetick_py-1.173.0 → onetick_py-1.175.0}/src/locator_parser/io.py +0 -0
  29. {onetick_py-1.173.0 → onetick_py-1.175.0}/src/locator_parser/locator.py +0 -0
  30. {onetick_py-1.173.0 → onetick_py-1.175.0}/src/onetick/__init__.py +0 -0
  31. {onetick_py-1.173.0 → onetick_py-1.175.0}/src/onetick/doc_utilities/__init__.py +0 -0
  32. {onetick_py-1.173.0 → onetick_py-1.175.0}/src/onetick/doc_utilities/napoleon.py +0 -0
  33. {onetick_py-1.173.0 → onetick_py-1.175.0}/src/onetick/doc_utilities/ot_doctest.py +0 -0
  34. {onetick_py-1.173.0 → onetick_py-1.175.0}/src/onetick/doc_utilities/snippets.py +0 -0
  35. {onetick_py-1.173.0 → onetick_py-1.175.0}/src/onetick/lib/__init__.py +0 -0
  36. {onetick_py-1.173.0 → onetick_py-1.175.0}/src/onetick/lib/instance.py +0 -0
  37. {onetick_py-1.173.0 → onetick_py-1.175.0}/src/onetick/py/__init__.py +0 -0
  38. {onetick_py-1.173.0 → onetick_py-1.175.0}/src/onetick/py/_stack_info.py +0 -0
  39. {onetick_py-1.173.0 → onetick_py-1.175.0}/src/onetick/py/aggregations/__init__.py +0 -0
  40. {onetick_py-1.173.0 → onetick_py-1.175.0}/src/onetick/py/aggregations/_docs.py +0 -0
  41. {onetick_py-1.173.0 → onetick_py-1.175.0}/src/onetick/py/aggregations/compute.py +0 -0
  42. {onetick_py-1.173.0 → onetick_py-1.175.0}/src/onetick/py/aggregations/functions.py +0 -0
  43. {onetick_py-1.173.0 → onetick_py-1.175.0}/src/onetick/py/aggregations/generic.py +0 -0
  44. {onetick_py-1.173.0 → onetick_py-1.175.0}/src/onetick/py/aggregations/high_low.py +0 -0
  45. {onetick_py-1.173.0 → onetick_py-1.175.0}/src/onetick/py/aggregations/num_distinct.py +0 -0
  46. {onetick_py-1.173.0 → onetick_py-1.175.0}/src/onetick/py/backports.py +0 -0
  47. {onetick_py-1.173.0 → onetick_py-1.175.0}/src/onetick/py/cache.py +0 -0
  48. {onetick_py-1.173.0 → onetick_py-1.175.0}/src/onetick/py/callback/__init__.py +0 -0
  49. {onetick_py-1.173.0 → onetick_py-1.175.0}/src/onetick/py/callback/callback.py +0 -0
  50. {onetick_py-1.173.0 → onetick_py-1.175.0}/src/onetick/py/callback/callbacks.py +0 -0
  51. {onetick_py-1.173.0 → onetick_py-1.175.0}/src/onetick/py/compatibility.py +0 -0
  52. {onetick_py-1.173.0 → onetick_py-1.175.0}/src/onetick/py/configuration.py +0 -0
  53. {onetick_py-1.173.0 → onetick_py-1.175.0}/src/onetick/py/core/__init__.py +0 -0
  54. {onetick_py-1.173.0 → onetick_py-1.175.0}/src/onetick/py/core/_csv_inspector.py +0 -0
  55. {onetick_py-1.173.0 → onetick_py-1.175.0}/src/onetick/py/core/_internal/__init__.py +0 -0
  56. {onetick_py-1.173.0 → onetick_py-1.175.0}/src/onetick/py/core/_internal/_manually_bound_value.py +0 -0
  57. {onetick_py-1.173.0 → onetick_py-1.175.0}/src/onetick/py/core/_internal/_nodes_history.py +0 -0
  58. {onetick_py-1.173.0 → onetick_py-1.175.0}/src/onetick/py/core/_internal/_op_utils/__init__.py +0 -0
  59. {onetick_py-1.173.0 → onetick_py-1.175.0}/src/onetick/py/core/_internal/_op_utils/every_operand.py +0 -0
  60. {onetick_py-1.173.0 → onetick_py-1.175.0}/src/onetick/py/core/_internal/_op_utils/is_const.py +0 -0
  61. {onetick_py-1.173.0 → onetick_py-1.175.0}/src/onetick/py/core/_internal/_per_tick_scripts/tick_list_sort_template.script +0 -0
  62. {onetick_py-1.173.0 → onetick_py-1.175.0}/src/onetick/py/core/_internal/_proxy_node.py +0 -0
  63. {onetick_py-1.173.0 → onetick_py-1.175.0}/src/onetick/py/core/_internal/_state_objects.py +0 -0
  64. {onetick_py-1.173.0 → onetick_py-1.175.0}/src/onetick/py/core/_internal/_state_vars.py +0 -0
  65. {onetick_py-1.173.0 → onetick_py-1.175.0}/src/onetick/py/core/_source/__init__.py +0 -0
  66. {onetick_py-1.173.0 → onetick_py-1.175.0}/src/onetick/py/core/_source/_symbol_param.py +0 -0
  67. {onetick_py-1.173.0 → onetick_py-1.175.0}/src/onetick/py/core/_source/schema.py +0 -0
  68. {onetick_py-1.173.0 → onetick_py-1.175.0}/src/onetick/py/core/_source/source_methods/__init__.py +0 -0
  69. {onetick_py-1.173.0 → onetick_py-1.175.0}/src/onetick/py/core/_source/source_methods/aggregations.py +0 -0
  70. {onetick_py-1.173.0 → onetick_py-1.175.0}/src/onetick/py/core/_source/source_methods/applyers.py +0 -0
  71. {onetick_py-1.173.0 → onetick_py-1.175.0}/src/onetick/py/core/_source/source_methods/columns.py +0 -0
  72. {onetick_py-1.173.0 → onetick_py-1.175.0}/src/onetick/py/core/_source/source_methods/data_quality.py +0 -0
  73. {onetick_py-1.173.0 → onetick_py-1.175.0}/src/onetick/py/core/_source/source_methods/debugs.py +0 -0
  74. {onetick_py-1.173.0 → onetick_py-1.175.0}/src/onetick/py/core/_source/source_methods/drops.py +0 -0
  75. {onetick_py-1.173.0 → onetick_py-1.175.0}/src/onetick/py/core/_source/source_methods/fields.py +0 -0
  76. {onetick_py-1.173.0 → onetick_py-1.175.0}/src/onetick/py/core/_source/source_methods/filters.py +0 -0
  77. {onetick_py-1.173.0 → onetick_py-1.175.0}/src/onetick/py/core/_source/source_methods/joins.py +0 -0
  78. {onetick_py-1.173.0 → onetick_py-1.175.0}/src/onetick/py/core/_source/source_methods/merges.py +0 -0
  79. {onetick_py-1.173.0 → onetick_py-1.175.0}/src/onetick/py/core/_source/source_methods/pandases.py +0 -0
  80. {onetick_py-1.173.0 → onetick_py-1.175.0}/src/onetick/py/core/_source/source_methods/renames.py +0 -0
  81. {onetick_py-1.173.0 → onetick_py-1.175.0}/src/onetick/py/core/_source/source_methods/sorts.py +0 -0
  82. {onetick_py-1.173.0 → onetick_py-1.175.0}/src/onetick/py/core/_source/source_methods/switches.py +0 -0
  83. {onetick_py-1.173.0 → onetick_py-1.175.0}/src/onetick/py/core/_source/source_methods/symbols.py +0 -0
  84. {onetick_py-1.173.0 → onetick_py-1.175.0}/src/onetick/py/core/_source/source_methods/times.py +0 -0
  85. {onetick_py-1.173.0 → onetick_py-1.175.0}/src/onetick/py/core/_source/source_methods/writes.py +0 -0
  86. {onetick_py-1.173.0 → onetick_py-1.175.0}/src/onetick/py/core/_source/symbol.py +0 -0
  87. {onetick_py-1.173.0 → onetick_py-1.175.0}/src/onetick/py/core/_source/tmp_otq.py +0 -0
  88. {onetick_py-1.173.0 → onetick_py-1.175.0}/src/onetick/py/core/column.py +0 -0
  89. {onetick_py-1.173.0 → onetick_py-1.175.0}/src/onetick/py/core/column_operations/__init__.py +0 -0
  90. {onetick_py-1.173.0 → onetick_py-1.175.0}/src/onetick/py/core/column_operations/_methods/__init__.py +0 -0
  91. {onetick_py-1.173.0 → onetick_py-1.175.0}/src/onetick/py/core/column_operations/_methods/_internal.py +0 -0
  92. {onetick_py-1.173.0 → onetick_py-1.175.0}/src/onetick/py/core/column_operations/_methods/methods.py +0 -0
  93. {onetick_py-1.173.0 → onetick_py-1.175.0}/src/onetick/py/core/column_operations/accessors/__init__.py +0 -0
  94. {onetick_py-1.173.0 → onetick_py-1.175.0}/src/onetick/py/core/column_operations/accessors/_accessor.py +0 -0
  95. {onetick_py-1.173.0 → onetick_py-1.175.0}/src/onetick/py/core/column_operations/accessors/decimal_accessor.py +0 -0
  96. {onetick_py-1.173.0 → onetick_py-1.175.0}/src/onetick/py/core/column_operations/accessors/dt_accessor.py +0 -0
  97. {onetick_py-1.173.0 → onetick_py-1.175.0}/src/onetick/py/core/column_operations/accessors/float_accessor.py +0 -0
  98. {onetick_py-1.173.0 → onetick_py-1.175.0}/src/onetick/py/core/column_operations/accessors/str_accessor.py +0 -0
  99. {onetick_py-1.173.0 → onetick_py-1.175.0}/src/onetick/py/core/cut_builder.py +0 -0
  100. {onetick_py-1.173.0 → onetick_py-1.175.0}/src/onetick/py/core/db_constants.py +0 -0
  101. {onetick_py-1.173.0 → onetick_py-1.175.0}/src/onetick/py/core/eval_query.py +0 -0
  102. {onetick_py-1.173.0 → onetick_py-1.175.0}/src/onetick/py/core/lambda_object.py +0 -0
  103. {onetick_py-1.173.0 → onetick_py-1.175.0}/src/onetick/py/core/multi_output_source.py +0 -0
  104. {onetick_py-1.173.0 → onetick_py-1.175.0}/src/onetick/py/core/per_tick_script.py +0 -0
  105. {onetick_py-1.173.0 → onetick_py-1.175.0}/src/onetick/py/core/query_inspector.py +0 -0
  106. {onetick_py-1.173.0 → onetick_py-1.175.0}/src/onetick/py/db/__init__.py +0 -0
  107. {onetick_py-1.173.0 → onetick_py-1.175.0}/src/onetick/py/db/_inspection.py +0 -0
  108. {onetick_py-1.173.0 → onetick_py-1.175.0}/src/onetick/py/db/db.py +0 -0
  109. {onetick_py-1.173.0 → onetick_py-1.175.0}/src/onetick/py/db/utils.py +0 -0
  110. {onetick_py-1.173.0 → onetick_py-1.175.0}/src/onetick/py/docs/__init__.py +0 -0
  111. {onetick_py-1.173.0 → onetick_py-1.175.0}/src/onetick/py/docs/docstring_parser.py +0 -0
  112. {onetick_py-1.173.0 → onetick_py-1.175.0}/src/onetick/py/docs/utils.py +0 -0
  113. {onetick_py-1.173.0 → onetick_py-1.175.0}/src/onetick/py/license.py +0 -0
  114. {onetick_py-1.173.0 → onetick_py-1.175.0}/src/onetick/py/log.py +0 -0
  115. {onetick_py-1.173.0 → onetick_py-1.175.0}/src/onetick/py/math.py +0 -0
  116. {onetick_py-1.173.0 → onetick_py-1.175.0}/src/onetick/py/misc.py +0 -0
  117. {onetick_py-1.173.0 → onetick_py-1.175.0}/src/onetick/py/oqd/__init__.py +0 -0
  118. {onetick_py-1.173.0 → onetick_py-1.175.0}/src/onetick/py/oqd/eps.py +0 -0
  119. {onetick_py-1.173.0 → onetick_py-1.175.0}/src/onetick/py/oqd/sources.py +0 -0
  120. {onetick_py-1.173.0 → onetick_py-1.175.0}/src/onetick/py/otq.py +0 -0
  121. {onetick_py-1.173.0 → onetick_py-1.175.0}/src/onetick/py/pyomd_mock.py +0 -0
  122. {onetick_py-1.173.0 → onetick_py-1.175.0}/src/onetick/py/run.py +0 -0
  123. {onetick_py-1.173.0 → onetick_py-1.175.0}/src/onetick/py/servers.py +0 -0
  124. {onetick_py-1.173.0 → onetick_py-1.175.0}/src/onetick/py/session.py +0 -0
  125. {onetick_py-1.173.0 → onetick_py-1.175.0}/src/onetick/py/sources/__init__.py +0 -0
  126. {onetick_py-1.173.0 → onetick_py-1.175.0}/src/onetick/py/sources/cache.py +0 -0
  127. {onetick_py-1.173.0 → onetick_py-1.175.0}/src/onetick/py/sources/common.py +0 -0
  128. {onetick_py-1.173.0 → onetick_py-1.175.0}/src/onetick/py/sources/csv.py +0 -0
  129. {onetick_py-1.173.0 → onetick_py-1.175.0}/src/onetick/py/sources/custom.py +0 -0
  130. {onetick_py-1.173.0 → onetick_py-1.175.0}/src/onetick/py/sources/data_file.py +0 -0
  131. {onetick_py-1.173.0 → onetick_py-1.175.0}/src/onetick/py/sources/data_source.py +0 -0
  132. {onetick_py-1.173.0 → onetick_py-1.175.0}/src/onetick/py/sources/empty.py +0 -0
  133. {onetick_py-1.173.0 → onetick_py-1.175.0}/src/onetick/py/sources/odbc.py +0 -0
  134. {onetick_py-1.173.0 → onetick_py-1.175.0}/src/onetick/py/sources/order_book.py +0 -0
  135. {onetick_py-1.173.0 → onetick_py-1.175.0}/src/onetick/py/sources/parquet.py +0 -0
  136. {onetick_py-1.173.0 → onetick_py-1.175.0}/src/onetick/py/sources/pit.py +0 -0
  137. {onetick_py-1.173.0 → onetick_py-1.175.0}/src/onetick/py/sources/query.py +0 -0
  138. {onetick_py-1.173.0 → onetick_py-1.175.0}/src/onetick/py/sources/snapshots.py +0 -0
  139. {onetick_py-1.173.0 → onetick_py-1.175.0}/src/onetick/py/sources/split_query_output_by_symbol.py +0 -0
  140. {onetick_py-1.173.0 → onetick_py-1.175.0}/src/onetick/py/sources/symbology_mapping.py +0 -0
  141. {onetick_py-1.173.0 → onetick_py-1.175.0}/src/onetick/py/sources/symbols.py +0 -0
  142. {onetick_py-1.173.0 → onetick_py-1.175.0}/src/onetick/py/sources/ticks.py +0 -0
  143. {onetick_py-1.173.0 → onetick_py-1.175.0}/src/onetick/py/sql.py +0 -0
  144. {onetick_py-1.173.0 → onetick_py-1.175.0}/src/onetick/py/state.py +0 -0
  145. {onetick_py-1.173.0 → onetick_py-1.175.0}/src/onetick/py/utils/__init__.py +0 -0
  146. {onetick_py-1.173.0 → onetick_py-1.175.0}/src/onetick/py/utils/acl.py +0 -0
  147. {onetick_py-1.173.0 → onetick_py-1.175.0}/src/onetick/py/utils/config.py +0 -0
  148. {onetick_py-1.173.0 → onetick_py-1.175.0}/src/onetick/py/utils/default.py +0 -0
  149. {onetick_py-1.173.0 → onetick_py-1.175.0}/src/onetick/py/utils/file.py +0 -0
  150. {onetick_py-1.173.0 → onetick_py-1.175.0}/src/onetick/py/utils/helpers.py +0 -0
  151. {onetick_py-1.173.0 → onetick_py-1.175.0}/src/onetick/py/utils/locator.py +0 -0
  152. {onetick_py-1.173.0 → onetick_py-1.175.0}/src/onetick/py/utils/perf.py +0 -0
  153. {onetick_py-1.173.0 → onetick_py-1.175.0}/src/onetick/py/utils/query.py +0 -0
  154. {onetick_py-1.173.0 → onetick_py-1.175.0}/src/onetick/py/utils/script.py +0 -0
  155. {onetick_py-1.173.0 → onetick_py-1.175.0}/src/onetick/py/utils/temp.py +0 -0
  156. {onetick_py-1.173.0 → onetick_py-1.175.0}/src/onetick/py/utils/tz.py +0 -0
  157. {onetick_py-1.173.0 → onetick_py-1.175.0}/src/onetick_py.egg-info/SOURCES.txt +0 -0
  158. {onetick_py-1.173.0 → onetick_py-1.175.0}/src/onetick_py.egg-info/dependency_links.txt +0 -0
  159. {onetick_py-1.173.0 → onetick_py-1.175.0}/src/onetick_py.egg-info/entry_points.txt +0 -0
  160. {onetick_py-1.173.0 → onetick_py-1.175.0}/src/onetick_py.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: onetick-py
3
- Version: 1.173.0
3
+ Version: 1.175.0
4
4
  Summary: Python package that allows you to work with OneTick
5
5
  Author-email: solutions <solutions@onetick.com>
6
6
  License-Expression: MIT
@@ -36,7 +36,7 @@ Requires-Dist: numpy==1.26.4; python_version == "3.12" and extra == "strict"
36
36
  Requires-Dist: pandas==1.5.2; python_version == "3.9" and extra == "strict"
37
37
  Requires-Dist: pandas==1.5.3; python_version == "3.10" and extra == "strict"
38
38
  Requires-Dist: pandas==1.5.3; python_version == "3.11" and extra == "strict"
39
- Requires-Dist: pandas==2.2.0; python_version == "3.12" and extra == "strict"
39
+ Requires-Dist: pandas==2.2.1; python_version == "3.12" and extra == "strict"
40
40
  Requires-Dist: pandas==2.3.0; python_version == "3.13" and extra == "strict"
41
41
  Requires-Dist: pandas==2.3.3; python_version == "3.14" and extra == "strict"
42
42
  Provides-Extra: webapi
@@ -5,6 +5,6 @@ numpy==1.26.4; python_version == '3.12'
5
5
  pandas==1.5.2; python_version == '3.9'
6
6
  pandas==1.5.3; python_version == '3.10'
7
7
  pandas==1.5.3; python_version == '3.11'
8
- pandas==2.2.0; python_version == '3.12'
8
+ pandas==2.2.1; python_version == '3.12'
9
9
  pandas==2.3.0; python_version == '3.13'
10
10
  pandas==2.3.3; python_version == '3.14'
@@ -1,2 +1,2 @@
1
1
  # This file was generated automatically. DO NOT CHANGE.
2
- VERSION = '1.173.0'
2
+ VERSION = '1.175.0'
@@ -547,7 +547,7 @@ class _AggregationTSSelection(_Aggregation):
547
547
 
548
548
  class _FloatAggregation(_Aggregation):
549
549
 
550
- require_type = (int, float, ott._inf)
550
+ require_type = (int, float, ott._inf, ott.decimal)
551
551
 
552
552
  """
553
553
  Aggregation that expect int or float as input
@@ -229,6 +229,9 @@ class ObSnapshot(_OrderBookAggregation):
229
229
  # we don't want to set hard limit on the output of order book aggregations
230
230
  if self.show_full_detail:
231
231
  kwargs['all_fields'] = True
232
+ self._size_type = int
233
+ if self.size_max_fractional_digits > 0:
234
+ self._size_type = float # type: ignore[assignment]
232
235
  super().__init__(*args, **kwargs)
233
236
 
234
237
  def _param_validation(self):
@@ -244,7 +247,7 @@ class ObSnapshot(_OrderBookAggregation):
244
247
  def _get_output_schema(self, src: 'Source', name: Optional[str] = None) -> dict:
245
248
  schema = {
246
249
  'PRICE': float,
247
- 'SIZE': int,
250
+ 'SIZE': self._size_type,
248
251
  'LEVEL': int,
249
252
  'UPDATE_TIME': otp.nsectime,
250
253
  'BUY_SELL_FLAG': int,
@@ -265,10 +268,10 @@ class ObSnapshotWide(ObSnapshot):
265
268
  def _get_output_schema(self, src: 'Source', name: Optional[str] = None) -> dict:
266
269
  schema = {
267
270
  'BID_PRICE': float,
268
- 'BID_SIZE': int,
271
+ 'BID_SIZE': self._size_type,
269
272
  'BID_UPDATE_TIME': otp.nsectime,
270
273
  'ASK_PRICE': float,
271
- 'ASK_SIZE': int,
274
+ 'ASK_SIZE': self._size_type,
272
275
  'ASK_UPDATE_TIME': otp.nsectime,
273
276
  'LEVEL': int,
274
277
  }
@@ -299,10 +302,10 @@ class ObSnapshotFlat(ObSnapshot):
299
302
  for level in range(1, self.max_levels + 1):
300
303
  schema.update({
301
304
  f'BID_PRICE{level}': float,
302
- f'BID_SIZE{level}': int,
305
+ f'BID_SIZE{level}': self._size_type,
303
306
  f'BID_UPDATE_TIME{level}': otp.nsectime,
304
307
  f'ASK_PRICE{level}': float,
305
- f'ASK_SIZE{level}': int,
308
+ f'ASK_SIZE{level}': self._size_type,
306
309
  f'ASK_UPDATE_TIME{level}': otp.nsectime,
307
310
  })
308
311
  return schema
@@ -343,6 +346,9 @@ class ObSummary(_OrderBookAggregation):
343
346
  self.state_key_max_inactivity_sec = state_key_max_inactivity_sec
344
347
  self.size_max_fractional_digits = size_max_fractional_digits
345
348
  self.include_market_order_ticks = include_market_order_ticks
349
+ self._size_type = int
350
+ if self.size_max_fractional_digits > 0:
351
+ self._size_type = float # type: ignore[assignment]
346
352
  super().__init__(*args, **kwargs)
347
353
 
348
354
  def _param_validation(self):
@@ -357,12 +363,12 @@ class ObSummary(_OrderBookAggregation):
357
363
 
358
364
  def _get_output_schema(self, src: 'Source', name: Optional[str] = None) -> dict:
359
365
  schema = {
360
- 'BID_SIZE': int,
366
+ 'BID_SIZE': self._size_type,
361
367
  'BID_VWAP': float,
362
368
  'BEST_BID_PRICE': float,
363
369
  'WORST_BID_PRICE': float,
364
370
  'NUM_BID_LEVELS': int,
365
- 'ASK_SIZE': int,
371
+ 'ASK_SIZE': self._size_type,
366
372
  'ASK_VWAP': float,
367
373
  'BEST_ASK_PRICE': float,
368
374
  'WORST_ASK_PRICE': float,
@@ -100,7 +100,7 @@ class Vwap(_Aggregation):
100
100
  FIELDS_TO_SKIP: List = ['column_name']
101
101
 
102
102
  output_field_type = float
103
- require_type = (int, float, ott.nsectime)
103
+ require_type = (int, float, ott.nsectime, ott.decimal)
104
104
 
105
105
  def __init__(self,
106
106
  price_column: str,
@@ -271,7 +271,7 @@ class Average(_FloatAggregation):
271
271
  class StdDev(_Aggregation): # Stddev does not support inf, so no need to use _FloatAggregation
272
272
  NAME = "STDDEV"
273
273
  EP = otq.Stddev
274
- require_type = (int, float)
274
+ require_type = (int, float, ott.decimal)
275
275
  output_field_type = float
276
276
  FIELDS_MAPPING = deepcopy(_Aggregation.FIELDS_MAPPING)
277
277
  FIELDS_MAPPING['biased'] = 'BIASED'
@@ -618,6 +618,9 @@ def pnl_realized(
618
618
  The name of the field with price, default is **PRICE**.
619
619
  buy_sell_flag_field: str, :py:class:`otp.Column <onetick.py.Column>`
620
620
  The name of the field with buy/sell flag, default is **BUY_SELL_FLAG**.
621
+ If the type of this field is string, then possible values are 'B' or 'b' for buy and 'S' or 's' for sell.
622
+ If the type of this field is integer, then possible values are 0 for buy and 1 for sell.
623
+
621
624
 
622
625
  See also
623
626
  --------
@@ -625,20 +628,63 @@ def pnl_realized(
625
628
 
626
629
  Examples
627
630
  --------
631
+ Let's generate some data:
628
632
 
629
- Simple usage
630
-
631
- >>> data = otp.DataSource('SOME_DATABASE', tick_type='TT', symbols='AA') # doctest: +SKIP
632
- >>> data = data.pnl_realized() # doctest: +SKIP
633
- >>> otp.run(data) # doctest: +SKIP
634
- Time BUY_SELL_FLAG PRICE SIZE PNL_REALIZED
635
- 0 2003-12-01 00:00:00.000 0 5 20 0.0
636
- 1 2003-12-01 00:00:00.001 0 4 30 0.0
637
- 2 2003-12-01 00:00:00.002 1 3 15 -30.0
638
- 3 2003-12-01 00:00:00.003 0 10 50 0.0
639
- 4 2003-12-01 00:00:00.004 1 7 18 49.0
640
- 5 2003-12-01 00:00:00.005 1 9 6 30.0
641
- 6 2003-12-01 00:00:00.006 0 8 40 0.0
633
+ >>> trades = otp.Ticks(
634
+ ... PRICE=[1.0, 2.0, 3.0, 2.5, 4.0, 5.0, 6.0, 7.0, 3.0, 4.0, 1.0],
635
+ ... SIZE=[700, 20, 570, 600, 100, 100, 100, 100, 150, 10, 100],
636
+ ... SELL_FLAG=[0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 1],
637
+ ... SIDE=['B', 'B', 'B', 'S', 'S', 'S', 'S', 'S', 'B', 'B', 'S'],
638
+ ... )
639
+ >>> otp.run(trades)
640
+ Time PRICE SIZE SELL_FLAG SIDE
641
+ 0 2003-12-01 00:00:00.000 1.0 700 0 B
642
+ 1 2003-12-01 00:00:00.001 2.0 20 0 B
643
+ 2 2003-12-01 00:00:00.002 3.0 570 0 B
644
+ 3 2003-12-01 00:00:00.003 2.5 600 1 S
645
+ 4 2003-12-01 00:00:00.004 4.0 100 1 S
646
+ 5 2003-12-01 00:00:00.005 5.0 100 1 S
647
+ 6 2003-12-01 00:00:00.006 6.0 100 1 S
648
+ 7 2003-12-01 00:00:00.007 7.0 100 1 S
649
+ 8 2003-12-01 00:00:00.008 3.0 150 0 B
650
+ 9 2003-12-01 00:00:00.009 4.0 10 0 B
651
+ 10 2003-12-01 00:00:00.010 1.0 100 1 S
652
+
653
+ And then calculate profit and loss metric for it.
654
+
655
+ First let's use string ``buy_sell_flag_field`` field:
656
+
657
+ >>> data = trades.pnl_realized(buy_sell_flag_field='SIDE') # doctest: +SKIP
658
+ >>> otp.run(data)[['Time', 'PRICE', 'SIZE', 'SIDE', 'PNL_REALIZED']] # doctest: +SKIP
659
+ Time PRICE SIZE SIDE PNL_REALIZED
660
+ 0 2003-12-01 00:00:00.000 1.0 700 B 0.0
661
+ 1 2003-12-01 00:00:00.001 2.0 20 B 0.0
662
+ 2 2003-12-01 00:00:00.002 3.0 570 B 0.0
663
+ 3 2003-12-01 00:00:00.003 2.5 600 S 900.0
664
+ 4 2003-12-01 00:00:00.004 4.0 100 S 300.0
665
+ 5 2003-12-01 00:00:00.005 5.0 100 S 220.0
666
+ 6 2003-12-01 00:00:00.006 6.0 100 S 300.0
667
+ 7 2003-12-01 00:00:00.007 7.0 100 S 400.0
668
+ 8 2003-12-01 00:00:00.008 3.0 150 B 0.0
669
+ 9 2003-12-01 00:00:00.009 4.0 10 B 0.0
670
+ 10 2003-12-01 00:00:00.010 1.0 100 S -200.0
671
+
672
+ We can get the same result using integer ``buy_sell_flag_field`` field:
673
+
674
+ >>> data = trades.pnl_realized(buy_sell_flag_field='SELL_FLAG') # doctest: +SKIP
675
+ >>> otp.run(data)[['Time', 'PRICE', 'SIZE', 'SELL_FLAG', 'PNL_REALIZED']] # doctest: +SKIP
676
+ Time PRICE SIZE SELL_FLAG PNL_REALIZED
677
+ 0 2003-12-01 00:00:00.000 1.0 700 0 0.0
678
+ 1 2003-12-01 00:00:00.001 2.0 20 0 0.0
679
+ 2 2003-12-01 00:00:00.002 3.0 570 0 0.0
680
+ 3 2003-12-01 00:00:00.003 2.5 600 1 900.0
681
+ 4 2003-12-01 00:00:00.004 4.0 100 1 300.0
682
+ 5 2003-12-01 00:00:00.005 5.0 100 1 220.0
683
+ 6 2003-12-01 00:00:00.006 6.0 100 1 300.0
684
+ 7 2003-12-01 00:00:00.007 7.0 100 1 400.0
685
+ 8 2003-12-01 00:00:00.008 3.0 150 0 0.0
686
+ 9 2003-12-01 00:00:00.009 4.0 10 0 0.0
687
+ 10 2003-12-01 00:00:00.010 1.0 100 1 -200.0
642
688
  """
643
689
  if computation_method not in ['fifo']:
644
690
  raise ValueError(
@@ -31,7 +31,7 @@ def float_to_str(prev_op, dtype=str):
31
31
  return MethodResult(op_str, dtype)
32
32
 
33
33
 
34
- def float_to_decimal(prev_op):
34
+ def num_to_decimal(prev_op):
35
35
  return MethodResult(f'decimal({str(prev_op)})', ott.decimal)
36
36
 
37
37
 
@@ -192,7 +192,7 @@ class _ConversionsDict(UserDict):
192
192
 
193
193
  CONVERSIONS = _ConversionsDict({(float, int): float_to_int,
194
194
  (float, str): float_to_str,
195
- (float, ott.decimal): float_to_decimal,
195
+ (float, ott.decimal): num_to_decimal,
196
196
  (ott.decimal, int): float_to_int,
197
197
  (ott.decimal, str): decimal_to_str,
198
198
  (ott.decimal, float): decimal_to_float,
@@ -206,6 +206,7 @@ CONVERSIONS = _ConversionsDict({(float, int): float_to_int,
206
206
  (int, float): int_to_float,
207
207
  (int, ott.nsectime): int_to_nsectime,
208
208
  (int, ott.msectime): int_to_msectime,
209
+ (int, ott.decimal): num_to_decimal,
209
210
  (str, float): str_to_float,
210
211
  (str, ott.decimal): str_to_decimal,
211
212
  (str, int): str_to_int,
@@ -8,9 +8,12 @@ from onetick.py import types as ott
8
8
 
9
9
 
10
10
  def are_numerics(*dtypes):
11
- return all(inspect.isclass(dtype)
12
- and (issubclass(dtype, (float, int)) or np.issubdtype(dtype, np.integer))
13
- and not issubclass(dtype, (ott.nsectime, ott.msectime)) for dtype in dtypes)
11
+ return all(
12
+ inspect.isclass(dtype)
13
+ and (issubclass(dtype, (float, int)) or np.issubdtype(dtype, np.integer) or issubclass(dtype, ott.decimal))
14
+ and not issubclass(dtype, (ott.nsectime, ott.msectime))
15
+ for dtype in dtypes
16
+ )
14
17
 
15
18
 
16
19
  def are_ints_not_time(*dtypes):
@@ -109,6 +112,12 @@ def _get_widest_type(left, right):
109
112
  (<class '...MyTime'>, None, <class '...MyNSec'>)
110
113
  """
111
114
 
115
+ # decimal takes precedence before integer and floating point types
116
+ if issubclass(left, ott.decimal) and are_numerics(right):
117
+ return left
118
+ if are_numerics(left) and issubclass(right, ott.decimal):
119
+ return right
120
+
112
121
  if issubclass(left, float) and issubclass(right, float):
113
122
  # between np.float and float we choose base float
114
123
  if left is not float and np.issubdtype(left, np.floating):
@@ -476,7 +476,7 @@ class Operation:
476
476
  Property that provides access to
477
477
  methods specific to float type.
478
478
  """
479
- if issubclass(self.dtype, float) and self.dtype is not ott.decimal:
479
+ if issubclass(self.dtype, float):
480
480
  from onetick.py.core.column_operations.accessors.float_accessor import _FloatAccessor
481
481
  return _FloatAccessor(self)
482
482
  else:
@@ -1043,7 +1043,7 @@ class Raw(Operation):
1043
1043
  def __init__(self, raw, dtype):
1044
1044
  if dtype is str:
1045
1045
  warnings.warn(
1046
- f'Be careful, default string length in OneTick is {ott.string.DEFAULT_LENGTH}.'
1046
+ f'Be careful, default string length in OneTick is {ott.string.DEFAULT_LENGTH}. '
1047
1047
  "Length of the result raw expression can't be calculated automatically, "
1048
1048
  "so you'd better use onetick.py.string type.",
1049
1049
  stacklevel=2,
@@ -947,7 +947,9 @@ class Source:
947
947
  view: bool = False,
948
948
  line_limit: Optional[Tuple[int, int]] = (10, 30),
949
949
  parse_eval_from_params: bool = False,
950
+ render_debug_info: bool = False,
950
951
  debug: bool = False,
952
+ graphviz_compat_mode: bool = False,
951
953
  **kwargs,
952
954
  ):
953
955
  """
@@ -973,8 +975,13 @@ class Source:
973
975
  If one of tuple values set to zero the corresponding limit disabled.
974
976
  parse_eval_from_params: bool
975
977
  Enable parsing and printing `eval` sub-queries from EP parameters.
978
+ render_debug_info: bool
979
+ Render additional debug information.
976
980
  debug: bool
977
981
  Allow to print stdout or stderr from `Graphviz` render.
982
+ graphviz_compat_mode: bool
983
+ Change internal parameters of result graph for better compatibility with old `Graphviz` versions.
984
+ Could produce larger and less readable graphs.
978
985
  kwargs:
979
986
  Additional arguments to be passed to :py:meth:`onetick.py.Source.to_otq` method (except
980
987
  ``file_name``, ``file_suffix`` and ``query_name`` parameters)
@@ -1006,7 +1013,8 @@ class Source:
1006
1013
 
1007
1014
  otq_path = self.to_otq(**kwargs)
1008
1015
  return render_otq(
1009
- otq_path, image_path, output_format, load_external_otqs, view, line_limit, parse_eval_from_params, debug,
1016
+ otq_path, image_path, output_format, load_external_otqs, view, line_limit, parse_eval_from_params,
1017
+ render_debug_info, debug, graphviz_compat_mode,
1010
1018
  )
1011
1019
 
1012
1020
  def copy(self, ep=None, columns=None, deep=False) -> 'Source':
@@ -327,6 +327,7 @@ def merge(sources, align_schema=True, symbols=None, identify_input_ts=False,
327
327
 
328
328
  if enforce_order:
329
329
  result.drop('OMDSEQ', inplace=True)
330
+ merged_columns.pop('OMDSEQ')
330
331
 
331
332
  if identify_input_ts:
332
333
  result.schema['SYMBOL_NAME' + added_field_name_suffix] = str
@@ -2030,7 +2031,7 @@ def _add_element(cur_res, element, format_spec_additional=None):
2030
2031
  if isinstance(element, Operation):
2031
2032
  if format_spec_additional is None:
2032
2033
  cur_res += element.apply(str)
2033
- elif issubclass(element.dtype, float) and re.fullmatch(r'\.\d+f', format_spec_additional):
2034
+ elif issubclass(element.dtype, (float, ott.decimal)) and re.fullmatch(r'\.\d+f', format_spec_additional):
2034
2035
  # float has strange behavior when precision=0
2035
2036
  decimal_elem = element.apply(ott.decimal)
2036
2037
  precision_str = re.findall(r'\d+', format_spec_additional)[0]
@@ -2047,7 +2048,7 @@ def _add_element(cur_res, element, format_spec_additional=None):
2047
2048
  else:
2048
2049
  if format_spec_additional is None:
2049
2050
  cur_res += str(element)
2050
- elif isinstance(element, float):
2051
+ elif isinstance(element, (float, ott.decimal)):
2051
2052
  formatting = f'{{:{format_spec_additional}}}'
2052
2053
  cur_res += formatting.format(element)
2053
2054
  else:
@@ -2,6 +2,7 @@ import ctypes
2
2
  import functools
3
3
  import inspect
4
4
  import warnings
5
+ import decimal as _decimal
5
6
  from typing import Optional, Type, Union
6
7
  from datetime import date as _date
7
8
  from datetime import datetime as _datetime
@@ -707,18 +708,23 @@ class _inf(float, metaclass=_nan_base):
707
708
  inf = _inf()
708
709
 
709
710
 
710
- class _decimal_str(type):
711
- def __str__(cls):
712
- return 'decimal'
713
-
714
-
715
- class decimal(float, metaclass=_decimal_str):
711
+ class decimal:
716
712
  """
717
713
  Object that represents decimal OneTick value.
718
714
  Decimal is 128 bit base 10 floating point number.
719
715
 
716
+ Parameters
717
+ ----------
718
+ value: int, float, str
719
+ The value to initialize decimal from.
720
+ Note that float values may be converted with precision lost.
721
+
720
722
  Examples
721
723
  --------
724
+
725
+ :py:class:`~onetick.py.types.decimal` objects can be used in tick generators
726
+ and column operations as any other onetick-py type:
727
+
722
728
  >>> t = otp.Ticks({'A': [otp.decimal(1), otp.decimal(2)]})
723
729
  >>> t['B'] = otp.decimal(1.23456789)
724
730
  >>> t['C'] = t['A'] / 0
@@ -727,43 +733,107 @@ class decimal(float, metaclass=_decimal_str):
727
733
  Time A B C D
728
734
  0 2003-12-01 00:00:00.000 1.0 1.234568 inf NaN
729
735
  1 2003-12-01 00:00:00.001 2.0 1.234568 inf NaN
730
- """
731
- def __wrap(self, res):
732
- # if parent class doesn't support some operation, it returns NotImplemented and so do we
733
- # In other case we wrap float result with our decimal class
734
- if isinstance(res, type(NotImplemented)):
735
- return NotImplemented
736
- return self.__class__(res)
737
-
738
- def __add__(self, other):
739
- return self.__wrap(super().__add__(other))
740
736
 
741
- def __radd__(self, other):
742
- return self.__wrap(super().__radd__(other))
743
-
744
- def __sub__(self, other):
745
- return self.__wrap(super().__sub__(other))
737
+ Additionally, any arithmetic operation with :py:class:`~onetick.py.types.decimal` object will return
738
+ an :py:class:`~onetick.py.Operation` object:
746
739
 
747
- def __rsub__(self, other):
748
- return self.__wrap(super().__rsub__(other))
740
+ >>> t = otp.Tick(A=1)
741
+ >>> t['X'] = otp.decimal(1) / 0
742
+ >>> otp.run(t)
743
+ Time A X
744
+ 0 2003-12-01 1 inf
745
+
746
+ Note that converting from float (first row) may result in losing precision.
747
+ :py:class:`~onetick.py.types.decimal` objects are created from strings or integers, so they don't lose precision:
748
+
749
+ >>> t0 = otp.Tick(A=0.1)
750
+ >>> t1 = otp.Tick(A=otp.decimal(0.01))
751
+ >>> t2 = otp.Tick(A=otp.decimal('0.001'))
752
+ >>> t3 = otp.Tick(A=otp.decimal(1) / otp.decimal(10_000))
753
+ >>> t = otp.merge([t0, t1, t2, t3], enforce_order=True)
754
+ >>> t['STR_A'] = t['A'].decimal.str(34)
755
+ >>> otp.run(t)
756
+ Time A STR_A
757
+ 0 2003-12-01 0.1000 0.1000000000000000055511151231257827
758
+ 1 2003-12-01 0.0100 0.0100000000000000000000000000000000
759
+ 2 2003-12-01 0.0010 0.0010000000000000000000000000000000
760
+ 3 2003-12-01 0.0001 0.0001000000000000000000000000000000
749
761
 
750
- def __mul__(self, other):
751
- return self.__wrap(super().__mul__(other))
762
+ Note that :py:class:`otp.Ticks <onetick.py.Ticks>` will convert everything from string under the hood,
763
+ so even the float values will not lose precision:
752
764
 
753
- def __rmul__(self, other):
754
- return self.__wrap(super().__rmul__(other))
765
+ >>> t = otp.Ticks({'A': [0.1, otp.decimal(0.01), otp.decimal('0.001'), otp.decimal(1e-4)]})
766
+ >>> t['STR_A'] = t['A'].decimal.str(34)
767
+ >>> otp.run(t)
768
+ Time A STR_A
769
+ 0 2003-12-01 00:00:00.000 0.1000 0.1000000000000000000000000000000000
770
+ 1 2003-12-01 00:00:00.001 0.0100 0.0100000000000000000000000000000000
771
+ 2 2003-12-01 00:00:00.002 0.0010 0.0010000000000000000000000000000000
772
+ 3 2003-12-01 00:00:00.003 0.0001 0.0001000000000000000000000000000000
773
+ """
774
+ def __new__(cls, *args, **kwargs):
775
+ # this method dynamically adds properties and methods
776
+ # from otp.Operation class to this one
777
+
778
+ # otp.decimal class doesn't fit well in onetick-py type system,
779
+ # so this class is a mix of both type and Operation logic
780
+
781
+ # Basically it works like this:
782
+ # otp.decimal is a OneTick type
783
+ # otp.decimal(1) is a decimal type object
784
+ # Doing anything with this object returns an otp.Operation:
785
+ # otp.decimal(1) / 2
786
+
787
+ def proxy_wrap(attr, value):
788
+ if callable(value):
789
+ @functools.wraps(value)
790
+ def f(self, *args, **kwargs):
791
+ op = self.to_operation()
792
+ return getattr(op, attr)(*args, **kwargs)
793
+ return f
794
+ else:
795
+ @functools.wraps(value)
796
+ def f(self):
797
+ op = self.to_operation()
798
+ return getattr(op, attr)
799
+ return property(f)
800
+
801
+ for attr, value in inspect.getmembers(otp.Operation):
802
+ # comparison methods are defined by default for some reason,
803
+ # but we want to get them from otp.Operation
804
+ if not hasattr(cls, attr) or attr in ('__lt__', '__le__', '__eq__', '__ne__', '__gt__', '__ge__'):
805
+ setattr(cls, attr, proxy_wrap(attr, value))
806
+
807
+ return super().__new__(cls)
808
+
809
+ def __init__(self, value):
810
+ supported_types = (str, int, float)
811
+ if not isinstance(value, supported_types):
812
+ raise TypeError("Parameter 'value' must be one of these types: {supported_types}")
813
+ self.__value = value
814
+
815
+ @classmethod
816
+ def _to_onetick_type_string(cls):
817
+ # called by ott.type2str
818
+ return 'decimal'
755
819
 
756
- def __truediv__(self, other):
757
- return self.__wrap(super().__truediv__(other))
820
+ def _to_onetick_string(self):
821
+ # called by ott.value2str
822
+ value = str(self.__value)
823
+ return f'STRING_TO_DECIMAL({value2str(value)})'
758
824
 
759
- def __rtruediv__(self, other):
760
- return self.__wrap(super().__rtruediv__(other))
825
+ def to_operation(self):
826
+ return otp.Operation(op_str=self._to_onetick_string(), dtype=decimal)
761
827
 
762
828
  def __str__(self):
763
- return super().__repr__()
829
+ # called by otp.CSV, we don't need to convert the value with OneTick functions in this case
830
+ return str(self.__value)
764
831
 
765
832
  def __repr__(self):
766
- return f"{self.__class__.__name__}({self})"
833
+ return f"{self.__class__.__name__}({value2str(self.__value)})"
834
+
835
+ def __format__(self, __format_spec: str) -> str:
836
+ return _decimal.Decimal(self.__value).__format__(__format_spec)
767
837
 
768
838
  # --------------------------------------------------------------- #
769
839
  # AUXILIARY FUNCTIONS
@@ -809,7 +879,7 @@ def get_source_base_type(value):
809
879
  value_type = nsectime
810
880
 
811
881
  # check valid value type
812
- if get_base_type(value_type) not in [int, float, str, bool]:
882
+ if get_base_type(value_type) not in [int, float, str, bool, decimal]:
813
883
  raise TypeError(f'Type "{repr(value_type)}" is not supported.')
814
884
 
815
885
  if not is_type_basic(value_type):
@@ -818,7 +888,7 @@ def get_source_base_type(value):
818
888
 
819
889
 
820
890
  def is_type_supported(dtype):
821
- return get_base_type(dtype) in [int, float, str, bool] or issubclass(dtype, (datetime, date))
891
+ return get_base_type(dtype) in [int, float, str, bool, decimal] or issubclass(dtype, (datetime, date))
822
892
 
823
893
 
824
894
  def get_base_type(obj):
@@ -830,6 +900,8 @@ def get_base_type(obj):
830
900
  return int
831
901
  elif issubclass(obj, float):
832
902
  return float
903
+ elif issubclass(obj, decimal):
904
+ return decimal
833
905
 
834
906
  return type(None)
835
907
 
@@ -1686,6 +1758,8 @@ def type2str(t):
1686
1758
  return "double"
1687
1759
  if t is None:
1688
1760
  return ''
1761
+ if t is decimal:
1762
+ return t._to_onetick_type_string()
1689
1763
  return str(t)
1690
1764
 
1691
1765
 
@@ -1841,15 +1915,16 @@ def value2str(v):
1841
1915
  # there is no escape, so replacing double quotes with concatenation with it
1842
1916
  return '"' + str(v).replace('"', '''"+'"'+"''') + '"'
1843
1917
 
1844
- if isinstance(v, (float, decimal)) and not (isinstance(v, (_inf, _nan))):
1918
+ if isinstance(v, decimal):
1919
+ return v._to_onetick_string()
1920
+
1921
+ if isinstance(v, float) and not (isinstance(v, (_inf, _nan))):
1845
1922
  # PY-286: support science notation
1846
1923
  s = str(v)
1847
1924
  if "e" in s:
1848
- s = f"{v:.20f}".rstrip("0")
1925
+ return f'atof({value2str(s)})'
1849
1926
  if s == "nan":
1850
1927
  return str(nan)
1851
- if isinstance(v, decimal):
1852
- return f'DECIMAL({s})'
1853
1928
  return s
1854
1929
 
1855
1930
  if is_time_type(v):
@@ -1960,7 +2035,7 @@ def default_by_type(dtype):
1960
2035
  >>> otp.default_by_type(float)
1961
2036
  nan
1962
2037
  >>> otp.default_by_type(otp.decimal)
1963
- decimal(0.0)
2038
+ decimal(0)
1964
2039
  >>> otp.default_by_type(int)
1965
2040
  0
1966
2041
  >>> otp.default_by_type(otp.ulong)