pfund 0.0.1.dev10__tar.gz → 0.0.1.dev11__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 (187) hide show
  1. {pfund-0.0.1.dev10 → pfund-0.0.1.dev11}/PKG-INFO +5 -1
  2. {pfund-0.0.1.dev10 → pfund-0.0.1.dev11}/pfund/CONTRIBUTING.md +3 -0
  3. {pfund-0.0.1.dev10 → pfund-0.0.1.dev11}/pfund/adapter.py +4 -7
  4. pfund-0.0.1.dev11/pfund/analyzer.py +198 -0
  5. pfund-0.0.1.dev11/pfund/config/binance/linear/config.yml +7 -0
  6. pfund-0.0.1.dev11/pfund/config/binance/linear/lot_sizes_linear.yml +2 -0
  7. pfund-0.0.1.dev11/pfund/config/binance/linear/pdt_matchings_linear.yml +2 -0
  8. pfund-0.0.1.dev11/pfund/config/binance/linear/tick_sizes_linear.yml +2 -0
  9. {pfund-0.0.1.dev10 → pfund-0.0.1.dev11}/pfund/config/configuration.py +5 -7
  10. {pfund-0.0.1.dev10 → pfund-0.0.1.dev11}/pfund/config_handler.py +4 -0
  11. {pfund-0.0.1.dev10 → pfund-0.0.1.dev11}/pfund/const/paths.py +1 -0
  12. {pfund-0.0.1.dev10 → pfund-0.0.1.dev11}/pfund/data_tools/data_tool_pandas.py +2 -6
  13. {pfund-0.0.1.dev10 → pfund-0.0.1.dev11}/pfund/engines/backtest_engine.py +16 -25
  14. {pfund-0.0.1.dev10 → pfund-0.0.1.dev11}/pfund/engines/trade_engine.py +7 -10
  15. pfund-0.0.1.dev11/pfund/exchanges/binance/__init__.py +3 -0
  16. pfund-0.0.1.dev11/pfund/exchanges/binance/exchange.py +37 -0
  17. pfund-0.0.1.dev11/pfund/exchanges/binance/linear/exchange.py +6 -0
  18. pfund-0.0.1.dev11/pfund/exchanges/binance/rest_api.py +15 -0
  19. pfund-0.0.1.dev11/pfund/exchanges/binance/ws_api.py +33 -0
  20. {pfund-0.0.1.dev10 → pfund-0.0.1.dev11}/pfund/exchanges/bybit/__init__.py +1 -2
  21. {pfund-0.0.1.dev10 → pfund-0.0.1.dev11}/pfund/exchanges/bybit/exchange.py +10 -6
  22. {pfund-0.0.1.dev10 → pfund-0.0.1.dev11}/pfund/exchanges/bybit/rest_api.py +3 -1
  23. {pfund-0.0.1.dev10 → pfund-0.0.1.dev11}/pfund/exchanges/bybit/ws_api.py +4 -2
  24. {pfund-0.0.1.dev10 → pfund-0.0.1.dev11}/pfund/exchanges/exchange_base.py +12 -9
  25. {pfund-0.0.1.dev10 → pfund-0.0.1.dev11}/pfund/managers/strategy_manager.py +1 -1
  26. pfund-0.0.1.dev11/pfund/templates/dashboards/pfund-overview.streamlit.py +0 -0
  27. pfund-0.0.1.dev11/pfund/templates/notebooks/pfund-analytics.ipynb +49 -0
  28. pfund-0.0.1.dev11/pfund/templates/notebooks/pfund-overview.ipynb +49 -0
  29. {pfund-0.0.1.dev10 → pfund-0.0.1.dev11}/pfund/utils/utils.py +11 -0
  30. {pfund-0.0.1.dev10 → pfund-0.0.1.dev11}/pyproject.toml +13 -3
  31. pfund-0.0.1.dev10/pfund/analyzer.py +0 -3
  32. {pfund-0.0.1.dev10 → pfund-0.0.1.dev11}/LICENSE +0 -0
  33. {pfund-0.0.1.dev10 → pfund-0.0.1.dev11}/README.md +0 -0
  34. {pfund-0.0.1.dev10 → pfund-0.0.1.dev11}/pfund/__init__.py +0 -0
  35. {pfund-0.0.1.dev10 → pfund-0.0.1.dev11}/pfund/accounts/__init__.py +0 -0
  36. {pfund-0.0.1.dev10 → pfund-0.0.1.dev11}/pfund/accounts/account_base.py +0 -0
  37. {pfund-0.0.1.dev10 → pfund-0.0.1.dev11}/pfund/accounts/account_crypto.py +0 -0
  38. {pfund-0.0.1.dev10 → pfund-0.0.1.dev11}/pfund/accounts/account_ib.py +0 -0
  39. {pfund-0.0.1.dev10 → pfund-0.0.1.dev11}/pfund/balances/__init__.py +0 -0
  40. {pfund-0.0.1.dev10 → pfund-0.0.1.dev11}/pfund/balances/balance_base.py +0 -0
  41. {pfund-0.0.1.dev10 → pfund-0.0.1.dev11}/pfund/balances/balance_crypto.py +0 -0
  42. {pfund-0.0.1.dev10 → pfund-0.0.1.dev11}/pfund/balances/balance_ib.py +0 -0
  43. {pfund-0.0.1.dev10 → pfund-0.0.1.dev11}/pfund/brokers/__init__.py +0 -0
  44. {pfund-0.0.1.dev10 → pfund-0.0.1.dev11}/pfund/brokers/broker_backtest.py +0 -0
  45. {pfund-0.0.1.dev10 → pfund-0.0.1.dev11}/pfund/brokers/broker_base.py +0 -0
  46. {pfund-0.0.1.dev10 → pfund-0.0.1.dev11}/pfund/brokers/broker_crypto.py +0 -0
  47. {pfund-0.0.1.dev10 → pfund-0.0.1.dev11}/pfund/brokers/broker_live.py +0 -0
  48. {pfund-0.0.1.dev10 → pfund-0.0.1.dev11}/pfund/brokers/ib/__init__.py +0 -0
  49. {pfund-0.0.1.dev10 → pfund-0.0.1.dev11}/pfund/brokers/ib/broker_ib.py +0 -0
  50. {pfund-0.0.1.dev10 → pfund-0.0.1.dev11}/pfund/brokers/ib/ib_api.py +0 -0
  51. {pfund-0.0.1.dev10 → pfund-0.0.1.dev11}/pfund/brokers/ib/ib_client.py +0 -0
  52. {pfund-0.0.1.dev10 → pfund-0.0.1.dev11}/pfund/brokers/ib/ib_wrapper.py +0 -0
  53. {pfund-0.0.1.dev10 → pfund-0.0.1.dev11}/pfund/cli/__init__.py +0 -0
  54. {pfund-0.0.1.dev10 → pfund-0.0.1.dev11}/pfund/cli/commands/__init__.py +0 -0
  55. {pfund-0.0.1.dev10 → pfund-0.0.1.dev11}/pfund/cli/commands/config.py +0 -0
  56. {pfund-0.0.1.dev10 → pfund-0.0.1.dev11}/pfund/cli/commands/docker_compose.py +0 -0
  57. {pfund-0.0.1.dev10 → pfund-0.0.1.dev11}/pfund/cli/main.py +0 -0
  58. {pfund-0.0.1.dev10 → pfund-0.0.1.dev11}/pfund/config/bybit/config.yml +0 -0
  59. {pfund-0.0.1.dev10 → pfund-0.0.1.dev11}/pfund/config/bybit/lot_sizes_inverse.yml +0 -0
  60. {pfund-0.0.1.dev10 → pfund-0.0.1.dev11}/pfund/config/bybit/lot_sizes_linear.yml +0 -0
  61. {pfund-0.0.1.dev10 → pfund-0.0.1.dev11}/pfund/config/bybit/lot_sizes_option.yml +0 -0
  62. {pfund-0.0.1.dev10 → pfund-0.0.1.dev11}/pfund/config/bybit/lot_sizes_spot.yml +0 -0
  63. {pfund-0.0.1.dev10 → pfund-0.0.1.dev11}/pfund/config/bybit/pdt_matchings_inverse.yml +0 -0
  64. {pfund-0.0.1.dev10 → pfund-0.0.1.dev11}/pfund/config/bybit/pdt_matchings_linear.yml +0 -0
  65. {pfund-0.0.1.dev10 → pfund-0.0.1.dev11}/pfund/config/bybit/pdt_matchings_option.yml +0 -0
  66. {pfund-0.0.1.dev10 → pfund-0.0.1.dev11}/pfund/config/bybit/pdt_matchings_spot.yml +0 -0
  67. {pfund-0.0.1.dev10 → pfund-0.0.1.dev11}/pfund/config/bybit/tick_sizes_inverse.yml +0 -0
  68. {pfund-0.0.1.dev10 → pfund-0.0.1.dev11}/pfund/config/bybit/tick_sizes_linear.yml +0 -0
  69. {pfund-0.0.1.dev10 → pfund-0.0.1.dev11}/pfund/config/bybit/tick_sizes_option.yml +0 -0
  70. {pfund-0.0.1.dev10 → pfund-0.0.1.dev11}/pfund/config/bybit/tick_sizes_spot.yml +0 -0
  71. {pfund-0.0.1.dev10 → pfund-0.0.1.dev11}/pfund/config/ib/config.yml +0 -0
  72. {pfund-0.0.1.dev10 → pfund-0.0.1.dev11}/pfund/config/logging.yml +0 -0
  73. {pfund-0.0.1.dev10 → pfund-0.0.1.dev11}/pfund/const/__init__.py +0 -0
  74. {pfund-0.0.1.dev10 → pfund-0.0.1.dev11}/pfund/const/_zmq_routes.py +0 -0
  75. {pfund-0.0.1.dev10 → pfund-0.0.1.dev11}/pfund/const/commons.py +0 -0
  76. {pfund-0.0.1.dev10 → pfund-0.0.1.dev11}/pfund/data_tools/data_tool_base.py +0 -0
  77. {pfund-0.0.1.dev10 → pfund-0.0.1.dev11}/pfund/datas/__init__.py +0 -0
  78. {pfund-0.0.1.dev10 → pfund-0.0.1.dev11}/pfund/datas/data_bar.py +0 -0
  79. {pfund-0.0.1.dev10 → pfund-0.0.1.dev11}/pfund/datas/data_base.py +0 -0
  80. {pfund-0.0.1.dev10 → pfund-0.0.1.dev11}/pfund/datas/data_quote.py +0 -0
  81. {pfund-0.0.1.dev10 → pfund-0.0.1.dev11}/pfund/datas/data_tick.py +0 -0
  82. {pfund-0.0.1.dev10 → pfund-0.0.1.dev11}/pfund/datas/data_time_based.py +0 -0
  83. {pfund-0.0.1.dev10 → pfund-0.0.1.dev11}/pfund/datas/resolution.py +0 -0
  84. {pfund-0.0.1.dev10 → pfund-0.0.1.dev11}/pfund/datas/timeframe.py +0 -0
  85. {pfund-0.0.1.dev10 → pfund-0.0.1.dev11}/pfund/engines/__init__.py +0 -0
  86. {pfund-0.0.1.dev10 → pfund-0.0.1.dev11}/pfund/engines/base_engine.py +0 -0
  87. {pfund-0.0.1.dev10 → pfund-0.0.1.dev11}/pfund/engines/test_engine.py +0 -0
  88. {pfund-0.0.1.dev10 → pfund-0.0.1.dev11}/pfund/engines/train_engine.py +0 -0
  89. {pfund-0.0.1.dev10 → pfund-0.0.1.dev11}/pfund/errors.py +0 -0
  90. {pfund-0.0.1.dev10 → pfund-0.0.1.dev11}/pfund/exchanges/__init__.py +0 -0
  91. {pfund-0.0.1.dev10 → pfund-0.0.1.dev11}/pfund/exchanges/bybit/rest_api_samples/get_markets_result_inverse +0 -0
  92. {pfund-0.0.1.dev10 → pfund-0.0.1.dev11}/pfund/exchanges/bybit/rest_api_samples/get_markets_result_linear +0 -0
  93. {pfund-0.0.1.dev10 → pfund-0.0.1.dev11}/pfund/exchanges/bybit/rest_api_samples/get_markets_result_option +0 -0
  94. {pfund-0.0.1.dev10 → pfund-0.0.1.dev11}/pfund/exchanges/bybit/rest_api_samples/get_markets_result_spot +0 -0
  95. {pfund-0.0.1.dev10 → pfund-0.0.1.dev11}/pfund/exchanges/bybit/rest_api_samples/get_markets_return_inverse +0 -0
  96. {pfund-0.0.1.dev10 → pfund-0.0.1.dev11}/pfund/exchanges/bybit/rest_api_samples/get_markets_return_linear +0 -0
  97. {pfund-0.0.1.dev10 → pfund-0.0.1.dev11}/pfund/exchanges/bybit/rest_api_samples/get_markets_return_option +0 -0
  98. {pfund-0.0.1.dev10 → pfund-0.0.1.dev11}/pfund/exchanges/bybit/rest_api_samples/get_markets_return_spot +0 -0
  99. {pfund-0.0.1.dev10 → pfund-0.0.1.dev11}/pfund/exchanges/rest_api_base.py +0 -0
  100. {pfund-0.0.1.dev10 → pfund-0.0.1.dev11}/pfund/exchanges/ws_api_base.py +0 -0
  101. {pfund-0.0.1.dev10 → pfund-0.0.1.dev11}/pfund/externals/ibapi/__init__.py +0 -0
  102. {pfund-0.0.1.dev10 → pfund-0.0.1.dev11}/pfund/externals/ibapi/account_summary_tags.py +0 -0
  103. {pfund-0.0.1.dev10 → pfund-0.0.1.dev11}/pfund/externals/ibapi/client.py +0 -0
  104. {pfund-0.0.1.dev10 → pfund-0.0.1.dev11}/pfund/externals/ibapi/comm.py +0 -0
  105. {pfund-0.0.1.dev10 → pfund-0.0.1.dev11}/pfund/externals/ibapi/commission_report.py +0 -0
  106. {pfund-0.0.1.dev10 → pfund-0.0.1.dev11}/pfund/externals/ibapi/common.py +0 -0
  107. {pfund-0.0.1.dev10 → pfund-0.0.1.dev11}/pfund/externals/ibapi/connection.py +0 -0
  108. {pfund-0.0.1.dev10 → pfund-0.0.1.dev11}/pfund/externals/ibapi/contract.py +0 -0
  109. {pfund-0.0.1.dev10 → pfund-0.0.1.dev11}/pfund/externals/ibapi/decoder.py +0 -0
  110. {pfund-0.0.1.dev10 → pfund-0.0.1.dev11}/pfund/externals/ibapi/enum_implem.py +0 -0
  111. {pfund-0.0.1.dev10 → pfund-0.0.1.dev11}/pfund/externals/ibapi/errors.py +0 -0
  112. {pfund-0.0.1.dev10 → pfund-0.0.1.dev11}/pfund/externals/ibapi/execution.py +0 -0
  113. {pfund-0.0.1.dev10 → pfund-0.0.1.dev11}/pfund/externals/ibapi/ibapi.pyproj +0 -0
  114. {pfund-0.0.1.dev10 → pfund-0.0.1.dev11}/pfund/externals/ibapi/message.py +0 -0
  115. {pfund-0.0.1.dev10 → pfund-0.0.1.dev11}/pfund/externals/ibapi/news.py +0 -0
  116. {pfund-0.0.1.dev10 → pfund-0.0.1.dev11}/pfund/externals/ibapi/object_implem.py +0 -0
  117. {pfund-0.0.1.dev10 → pfund-0.0.1.dev11}/pfund/externals/ibapi/order.py +0 -0
  118. {pfund-0.0.1.dev10 → pfund-0.0.1.dev11}/pfund/externals/ibapi/order_condition.py +0 -0
  119. {pfund-0.0.1.dev10 → pfund-0.0.1.dev11}/pfund/externals/ibapi/order_state.py +0 -0
  120. {pfund-0.0.1.dev10 → pfund-0.0.1.dev11}/pfund/externals/ibapi/orderdecoder.py +0 -0
  121. {pfund-0.0.1.dev10 → pfund-0.0.1.dev11}/pfund/externals/ibapi/reader.py +0 -0
  122. {pfund-0.0.1.dev10 → pfund-0.0.1.dev11}/pfund/externals/ibapi/scanner.py +0 -0
  123. {pfund-0.0.1.dev10 → pfund-0.0.1.dev11}/pfund/externals/ibapi/server_versions.py +0 -0
  124. {pfund-0.0.1.dev10 → pfund-0.0.1.dev11}/pfund/externals/ibapi/softdollartier.py +0 -0
  125. {pfund-0.0.1.dev10 → pfund-0.0.1.dev11}/pfund/externals/ibapi/tag_value.py +0 -0
  126. {pfund-0.0.1.dev10 → pfund-0.0.1.dev11}/pfund/externals/ibapi/ticktype.py +0 -0
  127. {pfund-0.0.1.dev10 → pfund-0.0.1.dev11}/pfund/externals/ibapi/utils.py +0 -0
  128. {pfund-0.0.1.dev10 → pfund-0.0.1.dev11}/pfund/externals/ibapi/wrapper.py +0 -0
  129. {pfund-0.0.1.dev10 → pfund-0.0.1.dev11}/pfund/indicators/__init__.py +0 -0
  130. {pfund-0.0.1.dev10 → pfund-0.0.1.dev11}/pfund/indicators/indicator_base.py +0 -0
  131. {pfund-0.0.1.dev10 → pfund-0.0.1.dev11}/pfund/indicators/ta_indicator.py +0 -0
  132. {pfund-0.0.1.dev10 → pfund-0.0.1.dev11}/pfund/indicators/talib_indicator.py +0 -0
  133. {pfund-0.0.1.dev10 → pfund-0.0.1.dev11}/pfund/investment_profile.py +0 -0
  134. {pfund-0.0.1.dev10 → pfund-0.0.1.dev11}/pfund/main.py +0 -0
  135. {pfund-0.0.1.dev10 → pfund-0.0.1.dev11}/pfund/managers/__init__.py +0 -0
  136. {pfund-0.0.1.dev10 → pfund-0.0.1.dev11}/pfund/managers/base_manager.py +0 -0
  137. {pfund-0.0.1.dev10 → pfund-0.0.1.dev11}/pfund/managers/connection_manager.py +0 -0
  138. {pfund-0.0.1.dev10 → pfund-0.0.1.dev11}/pfund/managers/data_manager.py +0 -0
  139. {pfund-0.0.1.dev10 → pfund-0.0.1.dev11}/pfund/managers/order_manager.py +0 -0
  140. {pfund-0.0.1.dev10 → pfund-0.0.1.dev11}/pfund/managers/portfolio_manager.py +0 -0
  141. {pfund-0.0.1.dev10 → pfund-0.0.1.dev11}/pfund/managers/risk_manager.py +0 -0
  142. {pfund-0.0.1.dev10 → pfund-0.0.1.dev11}/pfund/mixins/backtest.py +0 -0
  143. {pfund-0.0.1.dev10 → pfund-0.0.1.dev11}/pfund/models/__init__.py +0 -0
  144. {pfund-0.0.1.dev10 → pfund-0.0.1.dev11}/pfund/models/model_backtest.py +0 -0
  145. {pfund-0.0.1.dev10 → pfund-0.0.1.dev11}/pfund/models/model_base.py +0 -0
  146. {pfund-0.0.1.dev10 → pfund-0.0.1.dev11}/pfund/models/model_meta.py +0 -0
  147. {pfund-0.0.1.dev10 → pfund-0.0.1.dev11}/pfund/models/pytorch_model.py +0 -0
  148. {pfund-0.0.1.dev10 → pfund-0.0.1.dev11}/pfund/models/sklearn_model.py +0 -0
  149. {pfund-0.0.1.dev10 → pfund-0.0.1.dev11}/pfund/orders/__init__.py +0 -0
  150. {pfund-0.0.1.dev10 → pfund-0.0.1.dev11}/pfund/orders/order_base.py +0 -0
  151. {pfund-0.0.1.dev10 → pfund-0.0.1.dev11}/pfund/orders/order_crypto.py +0 -0
  152. {pfund-0.0.1.dev10 → pfund-0.0.1.dev11}/pfund/orders/order_ib.py +0 -0
  153. {pfund-0.0.1.dev10 → pfund-0.0.1.dev11}/pfund/orders/order_statuses.py +0 -0
  154. {pfund-0.0.1.dev10 → pfund-0.0.1.dev11}/pfund/orders/order_time_in_force.py +0 -0
  155. {pfund-0.0.1.dev10 → pfund-0.0.1.dev11}/pfund/plogging/__init__.py +0 -0
  156. {pfund-0.0.1.dev10 → pfund-0.0.1.dev11}/pfund/plogging/config.py +0 -0
  157. {pfund-0.0.1.dev10 → pfund-0.0.1.dev11}/pfund/plogging/filters.py +0 -0
  158. {pfund-0.0.1.dev10 → pfund-0.0.1.dev11}/pfund/plogging/formatter.py +0 -0
  159. {pfund-0.0.1.dev10 → pfund-0.0.1.dev11}/pfund/plogging/handlers.py +0 -0
  160. {pfund-0.0.1.dev10 → pfund-0.0.1.dev11}/pfund/portfolio.py +0 -0
  161. {pfund-0.0.1.dev10 → pfund-0.0.1.dev11}/pfund/positions/__init__.py +0 -0
  162. {pfund-0.0.1.dev10 → pfund-0.0.1.dev11}/pfund/positions/position_base.py +0 -0
  163. {pfund-0.0.1.dev10 → pfund-0.0.1.dev11}/pfund/positions/position_crypto.py +0 -0
  164. {pfund-0.0.1.dev10 → pfund-0.0.1.dev11}/pfund/positions/position_ib.py +0 -0
  165. {pfund-0.0.1.dev10 → pfund-0.0.1.dev11}/pfund/products/__init__.py +0 -0
  166. {pfund-0.0.1.dev10 → pfund-0.0.1.dev11}/pfund/products/product_base.py +0 -0
  167. {pfund-0.0.1.dev10 → pfund-0.0.1.dev11}/pfund/products/product_crypto.py +0 -0
  168. {pfund-0.0.1.dev10 → pfund-0.0.1.dev11}/pfund/products/product_ib.py +0 -0
  169. {pfund-0.0.1.dev10 → pfund-0.0.1.dev11}/pfund/risk_monitor.py +0 -0
  170. {pfund-0.0.1.dev10 → pfund-0.0.1.dev11}/pfund/strategies/__init__.py +0 -0
  171. {pfund-0.0.1.dev10 → pfund-0.0.1.dev11}/pfund/strategies/allocation_strategy.py +0 -0
  172. {pfund-0.0.1.dev10 → pfund-0.0.1.dev11}/pfund/strategies/diversification_strategy.py +0 -0
  173. {pfund-0.0.1.dev10 → pfund-0.0.1.dev11}/pfund/strategies/hedging_strategy.py +0 -0
  174. {pfund-0.0.1.dev10 → pfund-0.0.1.dev11}/pfund/strategies/optimization_strategy.py +0 -0
  175. {pfund-0.0.1.dev10 → pfund-0.0.1.dev11}/pfund/strategies/portfolio_strategy.py +0 -0
  176. {pfund-0.0.1.dev10 → pfund-0.0.1.dev11}/pfund/strategies/rebalancing_strategy.py +0 -0
  177. {pfund-0.0.1.dev10 → pfund-0.0.1.dev11}/pfund/strategies/strategy_backtest.py +0 -0
  178. {pfund-0.0.1.dev10 → pfund-0.0.1.dev11}/pfund/strategies/strategy_base.py +0 -0
  179. {pfund-0.0.1.dev10 → pfund-0.0.1.dev11}/pfund/strategies/strategy_meta.py +0 -0
  180. {pfund-0.0.1.dev10 → pfund-0.0.1.dev11}/pfund/types/backtest.py +0 -0
  181. /pfund-0.0.1.dev10/pfund/exchanges/bybit/types.py → /pfund-0.0.1.dev11/pfund/types/bybit.py +0 -0
  182. {pfund-0.0.1.dev10 → pfund-0.0.1.dev11}/pfund/types/common_literals.py +0 -0
  183. {pfund-0.0.1.dev10 → pfund-0.0.1.dev11}/pfund/types/core.py +0 -0
  184. {pfund-0.0.1.dev10 → pfund-0.0.1.dev11}/pfund/universe.py +0 -0
  185. {pfund-0.0.1.dev10 → pfund-0.0.1.dev11}/pfund/utils/aliases.py +0 -0
  186. {pfund-0.0.1.dev10 → pfund-0.0.1.dev11}/pfund/utils/envs.py +0 -0
  187. {pfund-0.0.1.dev10 → pfund-0.0.1.dev11}/pfund/zeromq.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: pfund
3
- Version: 0.0.1.dev10
3
+ Version: 0.0.1.dev11
4
4
  Summary: A Complete Algo-Trading Framework for Machine Learning, enabling trading across TradFi, CeFi and DeFi. Supports Vectorized and Event-Driven Backtesting, Paper and Live Trading
5
5
  Home-page: https://pfund.ai
6
6
  License: Apache-2.0
@@ -13,13 +13,16 @@ Classifier: Programming Language :: Python :: 3
13
13
  Classifier: Programming Language :: Python :: 3.10
14
14
  Classifier: Programming Language :: Python :: 3.11
15
15
  Classifier: Programming Language :: Python :: 3.12
16
+ Provides-Extra: analytics
16
17
  Provides-Extra: data
17
18
  Provides-Extra: ml
18
19
  Requires-Dist: click (>=8.1.7,<9.0.0)
19
20
  Requires-Dist: gitpython (>=3.1.43,<4.0.0)
20
21
  Requires-Dist: mlflow (>=2.11.3,<3.0.0) ; extra == "ml"
21
22
  Requires-Dist: orjson (>=3.9.14,<4.0.0) ; extra == "data"
23
+ Requires-Dist: papermill (>=2.5.0,<3.0.0) ; extra == "analytics"
22
24
  Requires-Dist: pfeed[boost,data,df] (>=0.0.1.dev10,<0.0.2) ; extra == "data"
25
+ Requires-Dist: pfolio[bayesian,data,portfolio,temporary] (>=0.0.1.dev4,<0.0.2) ; extra == "analytics"
23
26
  Requires-Dist: platformdirs (>=4.2.0,<5.0.0)
24
27
  Requires-Dist: python-dotenv (>=1.0.1,<2.0.0)
25
28
  Requires-Dist: python-telegram-bot (>=20.7,<21.0)
@@ -32,6 +35,7 @@ Requires-Dist: scikit-learn (>=1.4.0,<2.0.0) ; extra == "ml"
32
35
  Requires-Dist: ta (>=0.11.0,<0.12.0) ; extra == "ml"
33
36
  Requires-Dist: torch (>=2.1.2,<3.0.0) ; extra == "ml"
34
37
  Requires-Dist: tqdm (>=4.66.2,<5.0.0)
38
+ Requires-Dist: voila (>=0.5.6,<0.6.0) ; extra == "analytics"
35
39
  Requires-Dist: websocket-client (>=1.7.0,<2.0.0)
36
40
  Project-URL: Documentation, https://pfund-docs.pfund.ai
37
41
  Project-URL: Repository, https://github.com/PFund-Software-Ltd/pfund
@@ -16,4 +16,7 @@ git pull --recurse-submodules # = git pull + git submodule update --recursive
16
16
  ```bash
17
17
  # at the root directory, run:
18
18
  jb build docs/ [--all]
19
+
20
+ # check if external links are broken:
21
+ jb build docs/ --builder linkcheck
19
22
  ```
@@ -1,12 +1,10 @@
1
1
  import yaml
2
2
  import os
3
3
 
4
- from pfund.const.paths import PROJ_CONFIG_PATH
5
-
6
4
 
7
5
  class Adapter:
8
- def __init__(self, trading_venue, adapter_dict):
9
- self._trading_venue = trading_venue
6
+ def __init__(self, config_path, adapter_dict):
7
+ self.config_path = config_path
10
8
  self._adapter_dict = adapter_dict
11
9
  self._adapter = {}
12
10
  self._ref_keys = []
@@ -25,9 +23,8 @@ class Adapter:
25
23
  return pdt
26
24
 
27
25
  def load_pdt_matchings(self):
28
- file_path = f'{PROJ_CONFIG_PATH}/{self._trading_venue.lower()}'
29
26
  config_name = 'pdt_matchings'
30
- for file_name in os.listdir(file_path):
27
+ for file_name in os.listdir(self.config_path):
31
28
  if not file_name.startswith(config_name):
32
29
  continue
33
30
  file_splits = file_name.split('_')
@@ -35,7 +32,7 @@ class Adapter:
35
32
  category = file_splits[-1].split('.')[0]
36
33
  else:
37
34
  category = ''
38
- with open(file_path + '/' + file_name, 'r') as f:
35
+ with open(self.config_path + '/' + file_name, 'r') as f:
39
36
  if pdt_macthings := yaml.safe_load(f):
40
37
  for pdt, epdt in pdt_macthings.items():
41
38
  self.update(pdt, epdt, ref_key=category)
@@ -0,0 +1,198 @@
1
+ import os
2
+ from pathlib import Path
3
+
4
+ from typing import Literal
5
+
6
+ from pfund.utils import utils
7
+ from pfund.config_handler import ConfigHandler
8
+ from pfund.const.paths import PROJ_PATH
9
+
10
+
11
+ class Analyzer:
12
+ try:
13
+ Engine = utils.get_engine_class()
14
+ config = Engine.config
15
+ except:
16
+ config = ConfigHandler.load_config()
17
+
18
+ notebook_path = Path(config.notebook_path)
19
+ spreadsheet_path = Path(config.spreadsheet_path)
20
+ dashboard_path = Path(config.dashboard_path)
21
+
22
+ def __init__(self, data: dict | None=None):
23
+ self.data = data or {}
24
+
25
+ @staticmethod
26
+ def _is_file(template: str) -> bool:
27
+ if '\\' in template or '/' in template:
28
+ assert Path(template).resolve().is_file(), f"File {template} does not exist"
29
+ return True
30
+ return False
31
+
32
+ @staticmethod
33
+ def _derive_template_type(template: str) -> Literal['notebook', 'spreadsheet', 'dashboard']:
34
+ if '.ipynb' in template:
35
+ template_type = 'notebook'
36
+ elif '.grid' in template:
37
+ template_type = 'spreadsheet'
38
+ elif '.py' in template:
39
+ template_type = 'dashboard'
40
+ else:
41
+ raise ValueError(f"Template {template} is not a valid template, only .ipynb, .grid, .py are supported.")
42
+ return template_type
43
+
44
+ def _find_template(self, template: str) -> str:
45
+ '''Check if the template exists in pfund's templates or user's templates
46
+ e.g. template = 'notebook.ipynb' or 'spreadsheet.grid' or 'dashboard.py'
47
+ '''
48
+ template_type = self._derive_template_type(template)
49
+ pfund_templates_dir = PROJ_PATH / 'templates' / (template_type+'s')
50
+ user_templates_dir = getattr(self, f'{template_type}_path')
51
+ for templates_dir in [pfund_templates_dir, user_templates_dir]:
52
+ for file_name in os.listdir(templates_dir):
53
+ if template == file_name:
54
+ template_file_path = templates_dir / template
55
+ return str(template_file_path)
56
+ else:
57
+ raise FileNotFoundError(f"Template {template} not found in pfund's templates or user's templates")
58
+
59
+ def _get_editor_cmd(self, editor: Literal['vscode', 'pycharm']) -> str:
60
+ if editor == 'vscode':
61
+ cmd = 'code'
62
+ if utils.is_command_available(cmd):
63
+ return cmd
64
+ else:
65
+ print("VSCode command 'code' is not available, cannot open the output notebook")
66
+ elif editor == 'pycharm':
67
+ for cmd in ['charm', 'pycharm']:
68
+ if utils.is_command_available(cmd):
69
+ return cmd
70
+ else:
71
+ print("PyCharm commands 'charm'/'pycharm' are both not available, cannot open the output notebook")
72
+ else:
73
+ print(f"Editor '{editor}' is not supported, cannot open the output notebook")
74
+
75
+ def run_notebooks(
76
+ self,
77
+ notebooks: list[str] | str,
78
+ *voila_args,
79
+ data: dict | None=None,
80
+ display: bool=True,
81
+ port: int=8866,
82
+ show_results_only: bool=True,
83
+ open_outputs: bool=False,
84
+ outputs_path: str | None=None,
85
+ editor: Literal['vscode', 'pycharm']='vscode'
86
+ ) -> None:
87
+ '''
88
+ Args:
89
+ notebook:
90
+ - notebook_template's name
91
+ - notebook's full path in str or Path
92
+ voila_args: additional arguments to pass to voila
93
+ data: data to be analyzed, if None, use the data passed to the Analyzer instance during initialization
94
+ display: if True, display the notebook in voila
95
+ show_results_only: if True, display only the results (no source code) in voila
96
+ open_outputs: if True, open the output notebook in the editor
97
+ outputs_path: path to save the output notebooks, if None, do not save the output notebooks
98
+ '''
99
+ import subprocess
100
+ import papermill as pm
101
+
102
+ def _find_available_port(_port):
103
+ retry_num = 100
104
+ while retry_num:
105
+ if not utils.is_port_in_use(_port):
106
+ return _port
107
+ retry_num -= 1
108
+ _port += 1
109
+ else:
110
+ raise Exception(f"No available ports found starting from {_port - 100}, cannot display the notebook")
111
+
112
+ def _assert_voila_args_are_valid():
113
+ for arg in voila_args:
114
+ if not arg.startswith('--'):
115
+ raise ValueError(f"Voila argument '{arg}' should start with '--'")
116
+ if arg.startswith('--port='):
117
+ raise ValueError(f"Voila argument '{arg}' should not be passed in, use the 'port' argument instead")
118
+ if arg.startswith('--strip_sources='):
119
+ raise ValueError(f"Voila argument '{arg}' should not be passed in, use the 'show_results_only' argument instead")
120
+
121
+ voila_processes = []
122
+ nb_output_file_paths = []
123
+ if isinstance(notebooks, str):
124
+ notebooks = [notebooks]
125
+ data = data or self.data
126
+ if not data:
127
+ raise ValueError("No data passed in or stored in the Analyzer instance, please pass in the data to be analyzed.")
128
+
129
+ if open_outputs:
130
+ assert outputs_path is not None, f"{outputs_path=}, cannot open the output notebook without saving it."
131
+ editor_cmd = self._get_editor_cmd(editor)
132
+
133
+ _assert_voila_args_are_valid()
134
+ is_theme_provided = any(arg.startswith('--theme=') for arg in voila_args)
135
+ if not is_theme_provided:
136
+ default_theme = 'dark'
137
+ voila_args = [f'--theme={default_theme}', *voila_args]
138
+
139
+ try:
140
+ for notebook in notebooks:
141
+ if self._is_file(notebook):
142
+ nb_input_file_path: str = notebook
143
+ notebook = Path(notebook).name # e.g. 'notebook.ipynb'
144
+ else:
145
+ nb_input_file_path: str = self._find_template(notebook)
146
+ nb_output_file_path = Path(outputs_path or '.').resolve() / f'{notebook.replace(".ipynb", "")}_output.ipynb'
147
+ nb_output_file_path = str(nb_output_file_path)
148
+ nb_output_file_paths.append(nb_output_file_path)
149
+
150
+ print(f"Executing notebook: {notebook}")
151
+ pm.execute_notebook(
152
+ nb_input_file_path,
153
+ nb_output_file_path,
154
+ parameters=data
155
+ )
156
+
157
+ if open_outputs:
158
+ # e.g. code notebook_output.ipynb if using vscode
159
+ if editor_cmd:
160
+ subprocess.run([editor_cmd, nb_output_file_path])
161
+
162
+ if display:
163
+ port = _find_available_port(port)
164
+ is_last_notebook = (notebook == notebooks[-1])
165
+ subprocess_func = subprocess.run if is_last_notebook else subprocess.Popen
166
+ process = subprocess_func([
167
+ 'voila',
168
+ f'--port={port}',
169
+ f'--strip_sources={show_results_only}',
170
+ *voila_args,
171
+ nb_output_file_path
172
+ ])
173
+ voila_processes.append(process)
174
+ except KeyboardInterrupt:
175
+ print("KeyboardInterrupt: Stopping the execution of the notebooks")
176
+ except Exception:
177
+ raise
178
+ finally:
179
+ if outputs_path is None:
180
+ for nb_output_file_path in nb_output_file_paths:
181
+ print(f"{outputs_path=}, removing output notebook: {nb_output_file_path}")
182
+ os.remove(nb_output_file_path)
183
+ for process in voila_processes:
184
+ process.terminate()
185
+ process.wait()
186
+
187
+ def run_spreadsheets(
188
+ self,
189
+ spreadsheets: list[str] | str
190
+ ):
191
+ pass
192
+
193
+ # TODO:
194
+ def run_dashboards(
195
+ self,
196
+ dashboards: list[str] | str
197
+ ):
198
+ pass
@@ -0,0 +1,7 @@
1
+ ---
2
+ settings:
3
+ private_channels: []
4
+ ...
5
+ ---
6
+ adapter:
7
+ pdts: {}
@@ -0,0 +1,2 @@
1
+ # FIXME: fake
2
+ BTC_USDT_PERP: 0.001
@@ -0,0 +1,2 @@
1
+ BTC_USDT_PERP: BTCUSDT
2
+ ETH_USDT_PERP: ETHUSDT
@@ -0,0 +1,2 @@
1
+ # FIXME: fake
2
+ BTC_USDT_PERP: 0.01
@@ -2,23 +2,21 @@ import os
2
2
 
3
3
  import yaml
4
4
 
5
- from pfund.const.paths import PROJ_CONFIG_PATH
6
5
  from pfund.utils.utils import short_path
7
6
 
8
7
 
9
8
  class Configuration:
10
- def __init__(self, config_dir, config_name):
11
- self.config_dir = config_dir.lower()
9
+ def __init__(self, config_path, config_name):
10
+ self.config_path = config_path
12
11
  self.config_name = config_name
13
- self.config_path = f'{PROJ_CONFIG_PATH}/{self.config_dir}'
14
12
  self.configs = None
15
13
  self.reload()
16
14
 
17
15
  def reload(self):
18
16
  self.configs = self.read_config(self.config_name)
19
17
 
20
- def get_config_dir(self):
21
- return self.config_dir
18
+ def get_config_path(self):
19
+ return self.config_path
22
20
 
23
21
  def read_config(self, config_name):
24
22
  file_path = f'{self.config_path}/{config_name}.yml'
@@ -40,7 +38,7 @@ class Configuration:
40
38
  raise Exception(f'could not find section {section} for config {self.config_name}')
41
39
 
42
40
  def check_if_config_exists_and_not_empty(self, config_name):
43
- file_path = f'{PROJ_CONFIG_PATH}/{self.config_dir}/{config_name}.yml'
41
+ file_path = f'{self.config_path}/{config_name}.yml'
44
42
  if os.path.exists(file_path) and os.stat(file_path).st_size != 0:
45
43
  return True
46
44
  else:
@@ -98,6 +98,10 @@ class ConfigHandler:
98
98
  def dashboard_path(self):
99
99
  return f'{self.data_path}/templates/dashboards'
100
100
 
101
+ @property
102
+ def artifact_path(self):
103
+ return f'{self.data_path}/.artifacts'
104
+
101
105
  def __post_init__(self):
102
106
  self.logging_config = self.logging_config or {}
103
107
 
@@ -24,3 +24,4 @@ BACKTEST_PATH = DATA_PATH / 'backtests'
24
24
  NOTEBOOK_PATH = DATA_PATH / 'templates' / 'notebooks'
25
25
  SPREADSHEET_PATH = DATA_PATH / 'templates' / 'spreadsheets'
26
26
  DASHBOARD_PATH = DATA_PATH / 'templates' / 'dashboards'
27
+ ARTIFACT_PATH = DATA_PATH / '.artifacts'
@@ -151,12 +151,8 @@ class PandasDataTool(BaseDataTool):
151
151
  index=pd.MultiIndex(levels=[[]]*len(index_names), codes=[[]]*len(index_names), names=index_names)
152
152
  )
153
153
 
154
- def output_df_to_parquet(self, name: str, df: pd.DataFrame,path: str | Path):
155
- if '.parquet' not in name:
156
- name = name + '.parquet'
157
- if type(path) is str:
158
- path = Path(path)
159
- df.to_parquet(path / name)
154
+ def output_df_to_parquet(self, df: pd.DataFrame, file_path: str):
155
+ df.to_parquet(file_path)
160
156
 
161
157
  def _create_multi_index(self, index_data: dict, index_names: list[str]) -> pd.MultiIndex:
162
158
  return pd.MultiIndex.from_tuples([tuple(index_data[name] for name in index_names)], names=index_names)
@@ -88,11 +88,11 @@ class BacktestEngine(BaseEngine):
88
88
  def _generate_backtest_id() -> str:
89
89
  return uuid.uuid4().hex
90
90
 
91
- def _create_backtest_name(self, strat: str):
91
+ def _create_backtest_name(self, strat: str, backtest_id: str, backtest_id_length: int=12):
92
92
  local_tz = utils.get_local_timezone()
93
93
  utcnow = datetime.datetime.now(tz=local_tz).strftime('%Y-%m-%d_%H:%M:%S_UTC%z')
94
- backtest_id = self._generate_backtest_id()
95
- return '.'.join([strat, utcnow, backtest_id])
94
+ trimmed_backtest_id = backtest_id[:backtest_id_length]
95
+ return '.'.join([strat, utcnow, trimmed_backtest_id])
96
96
 
97
97
  @staticmethod
98
98
  def _generate_backtest_hash(strategy: BaseStrategy):
@@ -144,47 +144,36 @@ class BacktestEngine(BaseEngine):
144
144
  self._write_json(file_name, backtest_json)
145
145
  return backtest_json[backtest_hash]
146
146
 
147
- def _write_backtest_history(self, backtest_name: str, backtest_name_trimmed: str, start_time: float, end_time: float):
148
- splits = backtest_name.split('.')
149
- strat, backtest_id = splits[0], splits[-1]
147
+ def _output_backtest_results(self, strat: str, df, start_time: float, end_time: float):
150
148
  strategy = self.get_strategy(strat)
149
+ backtest_id = self._generate_backtest_id()
150
+ backtest_name = self._create_backtest_name(strat, backtest_id)
151
151
  local_tz = utils.get_local_timezone()
152
152
  duration = end_time - start_time
153
+ df_file_path = os.path.join(self.config.backtest_path, f'{backtest_name}.parquet')
153
154
  backtest_history = {
154
- 'settings': self.settings,
155
155
  'metadata': {
156
156
  'pfund_version': pf.__version__,
157
- 'backtest_name': backtest_name,
158
157
  'backtest_id': backtest_id,
159
158
  'backtest_iteration': self._generate_backtest_iteration(strategy),
160
159
  'duration': f'{duration:.2f}s' if duration > 1 else f'{duration*1000:.2f}ms',
161
160
  'start_time': datetime.datetime.fromtimestamp(start_time, tz=local_tz).strftime('%Y-%m-%dT%H:%M:%S%z'),
162
161
  'end_time': datetime.datetime.fromtimestamp(end_time, tz=local_tz).strftime('%Y-%m-%dT%H:%M:%S%z'),
162
+ 'settings': self.settings,
163
163
  },
164
164
  'strategy': strategy.to_dict(),
165
- 'results': {
166
- 'df_file_path': os.path.join(self.config.backtest_path, f'{backtest_name_trimmed}.parquet'),
167
- }
165
+ 'result': df_file_path
168
166
  }
169
- self._write_json(f'{backtest_name_trimmed}.json', backtest_history)
170
-
171
- def trim_backtest_name(self, backtest_name: str) -> str:
172
- splits = backtest_name.split('.')
173
- backtest_id_len = 12
174
- splits[-1] = splits[-1][:backtest_id_len]
175
- return '.'.join(splits)
167
+ self.data_tool.output_df_to_parquet(df, df_file_path)
168
+ self._write_json(f'{backtest_name}.json', backtest_history)
169
+ return backtest_history
176
170
 
177
- def output_backtest_results(self, strat: str, df, start_time: float, end_time: float):
178
- backtest_name = self._create_backtest_name(strat)
179
- backtest_name_trimmed = self.trim_backtest_name(backtest_name)
180
- self.data_tool.output_df_to_parquet(backtest_name_trimmed, df, self.config.backtest_path)
181
- self._write_backtest_history(backtest_name, backtest_name_trimmed, start_time, end_time)
182
-
183
171
  def run(self):
184
172
  for broker in self.brokers.values():
185
173
  broker.start()
186
174
  self.strategy_manager.start()
187
175
 
176
+ backtests = {}
188
177
  if self.mode == 'vectorized':
189
178
  for strat, strategy in self.strategy_manager.strategies.items():
190
179
  # _dummy strategy is only created for model training, do nothing
@@ -196,7 +185,8 @@ class BacktestEngine(BaseEngine):
196
185
  strategy.backtest()
197
186
  end_time = time.time()
198
187
  df = strategy.get_df()
199
- self.output_backtest_results(strat, df, start_time, end_time)
188
+ backtest_history: dict = self._output_backtest_results(strat, df, start_time, end_time)
189
+ backtests[strat] = backtest_history
200
190
  elif self.mode == 'event_driven':
201
191
  for strat, strategy in self.strategy_manager.strategies.items():
202
192
  if strat == '_dummy':
@@ -248,6 +238,7 @@ class BacktestEngine(BaseEngine):
248
238
  else:
249
239
  raise NotImplementedError(f'Backtesting mode {self.mode} is not supported')
250
240
  self.strategy_manager.stop(reason='finished backtesting')
241
+ return backtests
251
242
 
252
243
  def end(self):
253
244
  self.strategy_manager.stop(reason='finished backtesting')
@@ -22,7 +22,7 @@ import schedule
22
22
 
23
23
  from pfund.engines.base_engine import BaseEngine
24
24
  from pfund.brokers.broker_base import BaseBroker
25
- from pfund.utils.utils import flatten_dict
25
+ from pfund.utils.utils import flatten_dict, is_port_in_use
26
26
  from pfund.zeromq import ZeroMQ
27
27
  from pfund.config_handler import ConfigHandler
28
28
 
@@ -57,15 +57,12 @@ class TradeEngine(BaseEngine):
57
57
  def _assign_zmq_ports(self) -> dict:
58
58
  _assigned_ports = []
59
59
  def _is_port_available(_port):
60
- import socket
61
- with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
62
- _is_port_in_use = (s.connect_ex(('localhost', _port)) == 0)
63
- _is_port_assigned = (_port in _assigned_ports)
64
- if _is_port_in_use or _is_port_assigned:
65
- return False
66
- else:
67
- _assigned_ports.append(_port)
68
- return True
60
+ _is_port_assigned = (_port in _assigned_ports)
61
+ if is_port_in_use(_port) or _is_port_assigned:
62
+ return False
63
+ else:
64
+ _assigned_ports.append(_port)
65
+ return True
69
66
  def _get_port(start_port=None):
70
67
  _port = start_port or self._zmq_port
71
68
  if _is_port_available(_port):
@@ -0,0 +1,3 @@
1
+ from pfund.exchanges.binance.exchange import Exchange as Binance
2
+ from pfund.exchanges.binance.rest_api import RestApi as BinanceRestApi
3
+ from pfund.exchanges.binance.ws_api import WebsocketApi as BinanceWebsocketApi
@@ -0,0 +1,37 @@
1
+ from pathlib import Path
2
+
3
+ from pfund.exchanges.exchange_base import BaseExchange
4
+
5
+
6
+ class Exchange(BaseExchange):
7
+ SUPPORTED_CATEGORIES = ['linear', 'inverse', 'spot', 'option']
8
+ PTYPE_TO_CATEGORY = {
9
+ 'PERP': 'linear',
10
+ 'FUT': 'linear',
11
+ 'IPERP': 'inverse',
12
+ 'IFUT': 'inverse',
13
+ 'SPOT': 'spot',
14
+ 'OPT': 'option',
15
+ }
16
+ def __new__(cls, env: str, ptype: str):
17
+ from pfund.exchanges.binance.linear.exchange import ExchangeLinear
18
+
19
+ ptype = ptype.upper()
20
+ category = cls.PTYPE_TO_CATEGORY[ptype]
21
+
22
+ if category == 'linear':
23
+ instance = super().__new__(ExchangeLinear)
24
+ instance.category = category
25
+ return instance
26
+ # EXTEND: Add other categories
27
+ else:
28
+ raise ValueError(f"Invalid {category=}")
29
+
30
+ def __init__(self, env: str, ptype: str):
31
+ exch = Path(__file__).parent.name
32
+ super().__init__(env, exch)
33
+
34
+ # FIXME: temporarily override the method, remove it later
35
+ def _setup_configs(self):
36
+ pass
37
+
@@ -0,0 +1,6 @@
1
+ from pfund.exchanges.binance.exchange import Exchange
2
+
3
+
4
+ class ExchangeLinear(Exchange):
5
+ def __init__(self, env: str, ptype: str):
6
+ super().__init__(env, ptype)
@@ -0,0 +1,15 @@
1
+ from pathlib import Path
2
+
3
+ from pfund.exchanges.rest_api_base import BaseRestApi
4
+
5
+
6
+ # TODO:
7
+ class RestApi(BaseRestApi):
8
+ URLS = {}
9
+ PUBLIC_ENDPOINTS = {}
10
+ PRIVATE_ENDPOINTS = {}
11
+
12
+ def __init__(self, env):
13
+ exch = Path(__file__).parent.name
14
+ super().__init__(env, exch)
15
+
@@ -0,0 +1,33 @@
1
+ from pathlib import Path
2
+
3
+ from pfund.exchanges.ws_api_base import BaseWebsocketApi
4
+
5
+
6
+ # TODO
7
+ class WebsocketApi(BaseWebsocketApi):
8
+ URLS = {}
9
+
10
+ def __init__(self, env, adapter):
11
+ exch = Path(__file__).parent.name
12
+ super().__init__(env, exch, adapter)
13
+
14
+ def _on_message(self, ws, msg):
15
+ pass
16
+
17
+ def _authenticate(self, acc: str):
18
+ pass
19
+
20
+ def _create_ws_url(self, ws_name: str) -> str:
21
+ pass
22
+
23
+ def _create_public_channel(self, channel, product, **kwargs):
24
+ pass
25
+
26
+ def _create_private_channel(self, channel, **kwargs):
27
+ pass
28
+
29
+ def _subscribe(self, ws, full_channels: list[str]):
30
+ pass
31
+
32
+ def _unsubscribe(self, ws, full_channels: list[str]):
33
+ pass
@@ -1,4 +1,3 @@
1
- from pfund.products.product_crypto import CryptoProduct
2
1
  from pfund.exchanges.bybit.exchange import Exchange as Bybit
3
2
  from pfund.exchanges.bybit.rest_api import RestApi as BybitRestApi
4
- from pfund.exchanges.bybit.ws_api import WebsocketApi as BybitWebsocketApi
3
+ from pfund.exchanges.bybit.ws_api import WebsocketApi as BybitWebsocketApi
@@ -1,12 +1,15 @@
1
+ from __future__ import annotations
2
+
1
3
  import datetime
2
4
  from decimal import Decimal
5
+ from pathlib import Path
3
6
 
4
- from typing import Callable, Any
5
-
6
- from websocket import WebSocket
7
+ from typing import Callable, Any, TYPE_CHECKING
8
+ if TYPE_CHECKING:
9
+ from pfund.types.bybit import Category
10
+ from websocket import WebSocket
7
11
 
8
12
  from pfund.exchanges.exchange_base import BaseExchange
9
- from pfund.exchanges.bybit.types import Category
10
13
  from pfund.accounts import CryptoAccount
11
14
  from pfund.products import CryptoProduct
12
15
  from pfund.orders import CryptoOrder
@@ -31,8 +34,9 @@ class Exchange(BaseExchange):
31
34
  _MAX_NUM_OF_PLACE_BATCH_ORDERS = 20
32
35
  _MAX_NUM_OF_CANEL_BATCH_ORDERS = 20
33
36
 
34
- def __init__(self, env):
35
- super().__init__(env, 'BYBIT')
37
+ def __init__(self, env: str):
38
+ exch = Path(__file__).parent.name
39
+ super().__init__(env, exch)
36
40
 
37
41
  def _create_pdt_matchings_config(
38
42
  # general to exchanges
@@ -1,3 +1,4 @@
1
+ from pathlib import Path
1
2
  import urllib
2
3
  import hmac
3
4
  import hashlib
@@ -44,7 +45,8 @@ class RestApi(BaseRestApi):
44
45
  'get_balances': ('GET', '/v5/account/wallet-balance'),
45
46
  }
46
47
 
47
- def __init__(self, env, exch):
48
+ def __init__(self, env):
49
+ exch = Path(__file__).parent.name
48
50
  super().__init__(env, exch)
49
51
 
50
52
  def _authenticate(self, req, account):
@@ -1,4 +1,5 @@
1
1
  import time
2
+ from pathlib import Path
2
3
  try:
3
4
  import orjson as json
4
5
  except ImportError:
@@ -45,8 +46,9 @@ class WebsocketApi(BaseWebsocketApi):
45
46
  'spot': 10
46
47
  }
47
48
 
48
- def __init__(self, env, name, adapter):
49
- super().__init__(env, name, adapter)
49
+ def __init__(self, env, adapter):
50
+ exch = Path(__file__).parent.name
51
+ super().__init__(env, exch, adapter)
50
52
 
51
53
  def _ping(self):
52
54
  msg = {"op": "ping"}