pfund 0.0.1.dev2__tar.gz → 0.0.1.dev4__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 (162) hide show
  1. {pfund-0.0.1.dev2 → pfund-0.0.1.dev4}/PKG-INFO +8 -21
  2. {pfund-0.0.1.dev2 → pfund-0.0.1.dev4}/README.md +2 -13
  3. {pfund-0.0.1.dev2 → pfund-0.0.1.dev4}/pfund/__init__.py +12 -3
  4. pfund-0.0.1.dev4/pfund/cli/__init__.py +4 -0
  5. pfund-0.0.1.dev4/pfund/cli/commands/config.py +64 -0
  6. pfund-0.0.1.dev4/pfund/cli/commands/docker_compose.py +30 -0
  7. pfund-0.0.1.dev4/pfund/cli/main.py +18 -0
  8. {pfund-0.0.1.dev2 → pfund-0.0.1.dev4}/pfund/config/configuration.py +3 -3
  9. {pfund-0.0.1.dev2 → pfund-0.0.1.dev4}/pfund/config_handler.py +22 -16
  10. {pfund-0.0.1.dev2 → pfund-0.0.1.dev4}/pfund/const/paths.py +1 -0
  11. {pfund-0.0.1.dev2 → pfund-0.0.1.dev4}/pfund/engines/backtest_engine.py +1 -2
  12. {pfund-0.0.1.dev2 → pfund-0.0.1.dev4}/pfund/engines/base_engine.py +3 -2
  13. {pfund-0.0.1.dev2 → pfund-0.0.1.dev4}/pfund/exchanges/bybit/exchange.py +1 -1
  14. {pfund-0.0.1.dev2 → pfund-0.0.1.dev4}/pfund/exchanges/exchange_base.py +1 -1
  15. pfund-0.0.1.dev4/pfund/main.py +10 -0
  16. {pfund-0.0.1.dev2 → pfund-0.0.1.dev4}/pfund/mixins/backtest.py +14 -9
  17. pfund-0.0.1.dev4/pfund/models/__init__.py +6 -0
  18. {pfund-0.0.1.dev2 → pfund-0.0.1.dev4}/pfund/models/model_base.py +8 -5
  19. {pfund-0.0.1.dev2 → pfund-0.0.1.dev4}/pfund/plogging/__init__.py +10 -10
  20. {pfund-0.0.1.dev2 → pfund-0.0.1.dev4}/pfund/plogging/config.py +1 -2
  21. {pfund-0.0.1.dev2 → pfund-0.0.1.dev4}/pyproject.toml +17 -13
  22. pfund-0.0.1.dev2/pfund/models/__init__.py +0 -3
  23. {pfund-0.0.1.dev2 → pfund-0.0.1.dev4}/LICENSE +0 -0
  24. {pfund-0.0.1.dev2 → pfund-0.0.1.dev4}/pfund/accounts/__init__.py +0 -0
  25. {pfund-0.0.1.dev2 → pfund-0.0.1.dev4}/pfund/accounts/account_base.py +0 -0
  26. {pfund-0.0.1.dev2 → pfund-0.0.1.dev4}/pfund/accounts/account_crypto.py +0 -0
  27. {pfund-0.0.1.dev2 → pfund-0.0.1.dev4}/pfund/accounts/account_ib.py +0 -0
  28. {pfund-0.0.1.dev2 → pfund-0.0.1.dev4}/pfund/adapter.py +0 -0
  29. {pfund-0.0.1.dev2 → pfund-0.0.1.dev4}/pfund/balances/__init__.py +0 -0
  30. {pfund-0.0.1.dev2 → pfund-0.0.1.dev4}/pfund/balances/balance_base.py +0 -0
  31. {pfund-0.0.1.dev2 → pfund-0.0.1.dev4}/pfund/balances/balance_crypto.py +0 -0
  32. {pfund-0.0.1.dev2 → pfund-0.0.1.dev4}/pfund/balances/balance_ib.py +0 -0
  33. {pfund-0.0.1.dev2 → pfund-0.0.1.dev4}/pfund/brokers/__init__.py +0 -0
  34. {pfund-0.0.1.dev2 → pfund-0.0.1.dev4}/pfund/brokers/broker_backtest.py +0 -0
  35. {pfund-0.0.1.dev2 → pfund-0.0.1.dev4}/pfund/brokers/broker_base.py +0 -0
  36. {pfund-0.0.1.dev2 → pfund-0.0.1.dev4}/pfund/brokers/broker_crypto.py +0 -0
  37. {pfund-0.0.1.dev2 → pfund-0.0.1.dev4}/pfund/brokers/broker_live.py +0 -0
  38. {pfund-0.0.1.dev2 → pfund-0.0.1.dev4}/pfund/brokers/ib/__init__.py +0 -0
  39. {pfund-0.0.1.dev2 → pfund-0.0.1.dev4}/pfund/brokers/ib/broker_ib.py +0 -0
  40. {pfund-0.0.1.dev2 → pfund-0.0.1.dev4}/pfund/brokers/ib/ib_api.py +0 -0
  41. {pfund-0.0.1.dev2 → pfund-0.0.1.dev4}/pfund/brokers/ib/ib_client.py +0 -0
  42. {pfund-0.0.1.dev2 → pfund-0.0.1.dev4}/pfund/brokers/ib/ib_wrapper.py +0 -0
  43. {pfund-0.0.1.dev2/pfund/exchanges → pfund-0.0.1.dev4/pfund/cli/commands}/__init__.py +0 -0
  44. {pfund-0.0.1.dev2 → pfund-0.0.1.dev4}/pfund/config/bybit/config.yml +0 -0
  45. {pfund-0.0.1.dev2 → pfund-0.0.1.dev4}/pfund/config/bybit/lot_sizes_inverse.yml +0 -0
  46. {pfund-0.0.1.dev2 → pfund-0.0.1.dev4}/pfund/config/bybit/lot_sizes_linear.yml +0 -0
  47. {pfund-0.0.1.dev2 → pfund-0.0.1.dev4}/pfund/config/bybit/lot_sizes_option.yml +0 -0
  48. {pfund-0.0.1.dev2 → pfund-0.0.1.dev4}/pfund/config/bybit/lot_sizes_spot.yml +0 -0
  49. {pfund-0.0.1.dev2 → pfund-0.0.1.dev4}/pfund/config/bybit/pdt_matchings_inverse.yml +0 -0
  50. {pfund-0.0.1.dev2 → pfund-0.0.1.dev4}/pfund/config/bybit/pdt_matchings_linear.yml +0 -0
  51. {pfund-0.0.1.dev2 → pfund-0.0.1.dev4}/pfund/config/bybit/pdt_matchings_option.yml +0 -0
  52. {pfund-0.0.1.dev2 → pfund-0.0.1.dev4}/pfund/config/bybit/pdt_matchings_spot.yml +0 -0
  53. {pfund-0.0.1.dev2 → pfund-0.0.1.dev4}/pfund/config/bybit/tick_sizes_inverse.yml +0 -0
  54. {pfund-0.0.1.dev2 → pfund-0.0.1.dev4}/pfund/config/bybit/tick_sizes_linear.yml +0 -0
  55. {pfund-0.0.1.dev2 → pfund-0.0.1.dev4}/pfund/config/bybit/tick_sizes_option.yml +0 -0
  56. {pfund-0.0.1.dev2 → pfund-0.0.1.dev4}/pfund/config/bybit/tick_sizes_spot.yml +0 -0
  57. {pfund-0.0.1.dev2 → pfund-0.0.1.dev4}/pfund/config/ib/config.yml +0 -0
  58. {pfund-0.0.1.dev2 → pfund-0.0.1.dev4}/pfund/config/logging.yml +0 -0
  59. {pfund-0.0.1.dev2 → pfund-0.0.1.dev4}/pfund/const/__init__.py +0 -0
  60. {pfund-0.0.1.dev2 → pfund-0.0.1.dev4}/pfund/const/_zmq_routes.py +0 -0
  61. {pfund-0.0.1.dev2 → pfund-0.0.1.dev4}/pfund/const/commons.py +0 -0
  62. {pfund-0.0.1.dev2 → pfund-0.0.1.dev4}/pfund/data_tools/data_tool_base.py +0 -0
  63. {pfund-0.0.1.dev2 → pfund-0.0.1.dev4}/pfund/data_tools/data_tool_pandas.py +0 -0
  64. {pfund-0.0.1.dev2 → pfund-0.0.1.dev4}/pfund/datas/__init__.py +0 -0
  65. {pfund-0.0.1.dev2 → pfund-0.0.1.dev4}/pfund/datas/data_bar.py +0 -0
  66. {pfund-0.0.1.dev2 → pfund-0.0.1.dev4}/pfund/datas/data_base.py +0 -0
  67. {pfund-0.0.1.dev2 → pfund-0.0.1.dev4}/pfund/datas/data_quote.py +0 -0
  68. {pfund-0.0.1.dev2 → pfund-0.0.1.dev4}/pfund/datas/data_tick.py +0 -0
  69. {pfund-0.0.1.dev2 → pfund-0.0.1.dev4}/pfund/datas/data_time_based.py +0 -0
  70. {pfund-0.0.1.dev2 → pfund-0.0.1.dev4}/pfund/datas/resolution.py +0 -0
  71. {pfund-0.0.1.dev2 → pfund-0.0.1.dev4}/pfund/datas/timeframe.py +0 -0
  72. {pfund-0.0.1.dev2 → pfund-0.0.1.dev4}/pfund/engines/__init__.py +0 -0
  73. {pfund-0.0.1.dev2 → pfund-0.0.1.dev4}/pfund/engines/test_engine.py +0 -0
  74. {pfund-0.0.1.dev2 → pfund-0.0.1.dev4}/pfund/engines/trade_engine.py +0 -0
  75. {pfund-0.0.1.dev2 → pfund-0.0.1.dev4}/pfund/engines/train_engine.py +0 -0
  76. {pfund-0.0.1.dev2 → pfund-0.0.1.dev4}/pfund/errors.py +0 -0
  77. /pfund-0.0.1.dev2/pfund/main.py → /pfund-0.0.1.dev4/pfund/exchanges/__init__.py +0 -0
  78. {pfund-0.0.1.dev2 → pfund-0.0.1.dev4}/pfund/exchanges/bybit/__init__.py +0 -0
  79. {pfund-0.0.1.dev2 → pfund-0.0.1.dev4}/pfund/exchanges/bybit/rest_api.py +0 -0
  80. {pfund-0.0.1.dev2 → pfund-0.0.1.dev4}/pfund/exchanges/bybit/rest_api_samples/get_markets_result_inverse +0 -0
  81. {pfund-0.0.1.dev2 → pfund-0.0.1.dev4}/pfund/exchanges/bybit/rest_api_samples/get_markets_result_linear +0 -0
  82. {pfund-0.0.1.dev2 → pfund-0.0.1.dev4}/pfund/exchanges/bybit/rest_api_samples/get_markets_result_option +0 -0
  83. {pfund-0.0.1.dev2 → pfund-0.0.1.dev4}/pfund/exchanges/bybit/rest_api_samples/get_markets_result_spot +0 -0
  84. {pfund-0.0.1.dev2 → pfund-0.0.1.dev4}/pfund/exchanges/bybit/rest_api_samples/get_markets_return_inverse +0 -0
  85. {pfund-0.0.1.dev2 → pfund-0.0.1.dev4}/pfund/exchanges/bybit/rest_api_samples/get_markets_return_linear +0 -0
  86. {pfund-0.0.1.dev2 → pfund-0.0.1.dev4}/pfund/exchanges/bybit/rest_api_samples/get_markets_return_option +0 -0
  87. {pfund-0.0.1.dev2 → pfund-0.0.1.dev4}/pfund/exchanges/bybit/rest_api_samples/get_markets_return_spot +0 -0
  88. {pfund-0.0.1.dev2 → pfund-0.0.1.dev4}/pfund/exchanges/bybit/types.py +0 -0
  89. {pfund-0.0.1.dev2 → pfund-0.0.1.dev4}/pfund/exchanges/bybit/ws_api.py +0 -0
  90. {pfund-0.0.1.dev2 → pfund-0.0.1.dev4}/pfund/exchanges/rest_api_base.py +0 -0
  91. {pfund-0.0.1.dev2 → pfund-0.0.1.dev4}/pfund/exchanges/ws_api_base.py +0 -0
  92. {pfund-0.0.1.dev2 → pfund-0.0.1.dev4}/pfund/externals/ibapi/__init__.py +0 -0
  93. {pfund-0.0.1.dev2 → pfund-0.0.1.dev4}/pfund/externals/ibapi/account_summary_tags.py +0 -0
  94. {pfund-0.0.1.dev2 → pfund-0.0.1.dev4}/pfund/externals/ibapi/client.py +0 -0
  95. {pfund-0.0.1.dev2 → pfund-0.0.1.dev4}/pfund/externals/ibapi/comm.py +0 -0
  96. {pfund-0.0.1.dev2 → pfund-0.0.1.dev4}/pfund/externals/ibapi/commission_report.py +0 -0
  97. {pfund-0.0.1.dev2 → pfund-0.0.1.dev4}/pfund/externals/ibapi/common.py +0 -0
  98. {pfund-0.0.1.dev2 → pfund-0.0.1.dev4}/pfund/externals/ibapi/connection.py +0 -0
  99. {pfund-0.0.1.dev2 → pfund-0.0.1.dev4}/pfund/externals/ibapi/contract.py +0 -0
  100. {pfund-0.0.1.dev2 → pfund-0.0.1.dev4}/pfund/externals/ibapi/decoder.py +0 -0
  101. {pfund-0.0.1.dev2 → pfund-0.0.1.dev4}/pfund/externals/ibapi/enum_implem.py +0 -0
  102. {pfund-0.0.1.dev2 → pfund-0.0.1.dev4}/pfund/externals/ibapi/errors.py +0 -0
  103. {pfund-0.0.1.dev2 → pfund-0.0.1.dev4}/pfund/externals/ibapi/execution.py +0 -0
  104. {pfund-0.0.1.dev2 → pfund-0.0.1.dev4}/pfund/externals/ibapi/ibapi.pyproj +0 -0
  105. {pfund-0.0.1.dev2 → pfund-0.0.1.dev4}/pfund/externals/ibapi/message.py +0 -0
  106. {pfund-0.0.1.dev2 → pfund-0.0.1.dev4}/pfund/externals/ibapi/news.py +0 -0
  107. {pfund-0.0.1.dev2 → pfund-0.0.1.dev4}/pfund/externals/ibapi/object_implem.py +0 -0
  108. {pfund-0.0.1.dev2 → pfund-0.0.1.dev4}/pfund/externals/ibapi/order.py +0 -0
  109. {pfund-0.0.1.dev2 → pfund-0.0.1.dev4}/pfund/externals/ibapi/order_condition.py +0 -0
  110. {pfund-0.0.1.dev2 → pfund-0.0.1.dev4}/pfund/externals/ibapi/order_state.py +0 -0
  111. {pfund-0.0.1.dev2 → pfund-0.0.1.dev4}/pfund/externals/ibapi/orderdecoder.py +0 -0
  112. {pfund-0.0.1.dev2 → pfund-0.0.1.dev4}/pfund/externals/ibapi/reader.py +0 -0
  113. {pfund-0.0.1.dev2 → pfund-0.0.1.dev4}/pfund/externals/ibapi/scanner.py +0 -0
  114. {pfund-0.0.1.dev2 → pfund-0.0.1.dev4}/pfund/externals/ibapi/server_versions.py +0 -0
  115. {pfund-0.0.1.dev2 → pfund-0.0.1.dev4}/pfund/externals/ibapi/softdollartier.py +0 -0
  116. {pfund-0.0.1.dev2 → pfund-0.0.1.dev4}/pfund/externals/ibapi/tag_value.py +0 -0
  117. {pfund-0.0.1.dev2 → pfund-0.0.1.dev4}/pfund/externals/ibapi/ticktype.py +0 -0
  118. {pfund-0.0.1.dev2 → pfund-0.0.1.dev4}/pfund/externals/ibapi/utils.py +0 -0
  119. {pfund-0.0.1.dev2 → pfund-0.0.1.dev4}/pfund/externals/ibapi/wrapper.py +0 -0
  120. {pfund-0.0.1.dev2 → pfund-0.0.1.dev4}/pfund/indicators/__init__.py +0 -0
  121. {pfund-0.0.1.dev2 → pfund-0.0.1.dev4}/pfund/indicators/indicator_base.py +0 -0
  122. {pfund-0.0.1.dev2 → pfund-0.0.1.dev4}/pfund/indicators/ta_indicator.py +0 -0
  123. {pfund-0.0.1.dev2 → pfund-0.0.1.dev4}/pfund/indicators/talib_indicator.py +0 -0
  124. {pfund-0.0.1.dev2 → pfund-0.0.1.dev4}/pfund/managers/__init__.py +0 -0
  125. {pfund-0.0.1.dev2 → pfund-0.0.1.dev4}/pfund/managers/base_manager.py +0 -0
  126. {pfund-0.0.1.dev2 → pfund-0.0.1.dev4}/pfund/managers/connection_manager.py +0 -0
  127. {pfund-0.0.1.dev2 → pfund-0.0.1.dev4}/pfund/managers/data_manager.py +0 -0
  128. {pfund-0.0.1.dev2 → pfund-0.0.1.dev4}/pfund/managers/order_manager.py +0 -0
  129. {pfund-0.0.1.dev2 → pfund-0.0.1.dev4}/pfund/managers/portfolio_manager.py +0 -0
  130. {pfund-0.0.1.dev2 → pfund-0.0.1.dev4}/pfund/managers/risk_manager.py +0 -0
  131. {pfund-0.0.1.dev2 → pfund-0.0.1.dev4}/pfund/managers/strategy_manager.py +0 -0
  132. {pfund-0.0.1.dev2 → pfund-0.0.1.dev4}/pfund/models/model_backtest.py +0 -0
  133. {pfund-0.0.1.dev2 → pfund-0.0.1.dev4}/pfund/models/model_meta.py +0 -0
  134. {pfund-0.0.1.dev2 → pfund-0.0.1.dev4}/pfund/models/pytorch_model.py +0 -0
  135. {pfund-0.0.1.dev2 → pfund-0.0.1.dev4}/pfund/models/sklearn_model.py +0 -0
  136. {pfund-0.0.1.dev2 → pfund-0.0.1.dev4}/pfund/orders/__init__.py +0 -0
  137. {pfund-0.0.1.dev2 → pfund-0.0.1.dev4}/pfund/orders/order_base.py +0 -0
  138. {pfund-0.0.1.dev2 → pfund-0.0.1.dev4}/pfund/orders/order_crypto.py +0 -0
  139. {pfund-0.0.1.dev2 → pfund-0.0.1.dev4}/pfund/orders/order_ib.py +0 -0
  140. {pfund-0.0.1.dev2 → pfund-0.0.1.dev4}/pfund/orders/order_statuses.py +0 -0
  141. {pfund-0.0.1.dev2 → pfund-0.0.1.dev4}/pfund/orders/order_time_in_force.py +0 -0
  142. {pfund-0.0.1.dev2 → pfund-0.0.1.dev4}/pfund/plogging/filters.py +0 -0
  143. {pfund-0.0.1.dev2 → pfund-0.0.1.dev4}/pfund/plogging/formatter.py +0 -0
  144. {pfund-0.0.1.dev2 → pfund-0.0.1.dev4}/pfund/plogging/handlers.py +0 -0
  145. {pfund-0.0.1.dev2 → pfund-0.0.1.dev4}/pfund/portfolio.py +0 -0
  146. {pfund-0.0.1.dev2 → pfund-0.0.1.dev4}/pfund/positions/__init__.py +0 -0
  147. {pfund-0.0.1.dev2 → pfund-0.0.1.dev4}/pfund/positions/position_base.py +0 -0
  148. {pfund-0.0.1.dev2 → pfund-0.0.1.dev4}/pfund/positions/position_crypto.py +0 -0
  149. {pfund-0.0.1.dev2 → pfund-0.0.1.dev4}/pfund/positions/position_ib.py +0 -0
  150. {pfund-0.0.1.dev2 → pfund-0.0.1.dev4}/pfund/products/__init__.py +0 -0
  151. {pfund-0.0.1.dev2 → pfund-0.0.1.dev4}/pfund/products/product_base.py +0 -0
  152. {pfund-0.0.1.dev2 → pfund-0.0.1.dev4}/pfund/products/product_crypto.py +0 -0
  153. {pfund-0.0.1.dev2 → pfund-0.0.1.dev4}/pfund/products/product_ib.py +0 -0
  154. {pfund-0.0.1.dev2 → pfund-0.0.1.dev4}/pfund/risk_monitor.py +0 -0
  155. {pfund-0.0.1.dev2 → pfund-0.0.1.dev4}/pfund/strategies/__init__.py +0 -0
  156. {pfund-0.0.1.dev2 → pfund-0.0.1.dev4}/pfund/strategies/strategy_backtest.py +0 -0
  157. {pfund-0.0.1.dev2 → pfund-0.0.1.dev4}/pfund/strategies/strategy_base.py +0 -0
  158. {pfund-0.0.1.dev2 → pfund-0.0.1.dev4}/pfund/strategies/strategy_meta.py +0 -0
  159. {pfund-0.0.1.dev2 → pfund-0.0.1.dev4}/pfund/utils/aliases.py +0 -0
  160. {pfund-0.0.1.dev2 → pfund-0.0.1.dev4}/pfund/utils/envs.py +0 -0
  161. {pfund-0.0.1.dev2 → pfund-0.0.1.dev4}/pfund/utils/utils.py +0 -0
  162. {pfund-0.0.1.dev2 → pfund-0.0.1.dev4}/pfund/zeromq.py +0 -0
@@ -1,23 +1,21 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: pfund
3
- Version: 0.0.1.dev2
3
+ Version: 0.0.1.dev4
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
7
7
  Keywords: trading,algo-trading,stocks,cryptos,cryptocurrencies,TradFi,CeFi,DeFi,portfolio management,investment,backtesting,machine learning
8
8
  Author: Stephen Yau
9
9
  Author-email: softwareentrepreneer+pfund@gmail.com
10
- Requires-Python: >=3.10,<4.0
10
+ Requires-Python: >=3.10,<3.12
11
11
  Classifier: License :: OSI Approved :: Apache Software License
12
12
  Classifier: Programming Language :: Python :: 3
13
13
  Classifier: Programming Language :: Python :: 3.10
14
14
  Classifier: Programming Language :: Python :: 3.11
15
- Classifier: Programming Language :: Python :: 3.12
16
- Provides-Extra: ml
17
15
  Requires-Dist: click (>=8.1.7,<9.0.0)
18
- Requires-Dist: orjson (>=3.9.12,<4.0.0)
16
+ Requires-Dist: orjson (>=3.9.14,<4.0.0)
19
17
  Requires-Dist: pandas (>=2.2.0,<3.0.0)
20
- Requires-Dist: pfeed (>=0.0.1.dev1,<0.0.2)
18
+ Requires-Dist: pfeed (>=0.0.1.dev4,<0.0.2)
21
19
  Requires-Dist: platformdirs (>=4.2.0,<5.0.0)
22
20
  Requires-Dist: psutil (>=5.9.8,<6.0.0)
23
21
  Requires-Dist: python-telegram-bot (>=20.7,<21.0)
@@ -25,9 +23,9 @@ Requires-Dist: pyyaml (>=6.0.1,<7.0.0)
25
23
  Requires-Dist: pyzmq (>=25.1.2,<26.0.0)
26
24
  Requires-Dist: rich (>=13.7.0,<14.0.0)
27
25
  Requires-Dist: schedule (>=1.2.1,<2.0.0)
28
- Requires-Dist: scikit-learn (>=1.4.0,<2.0.0) ; extra == "ml"
26
+ Requires-Dist: scikit-learn (>=1.4.0,<2.0.0)
29
27
  Requires-Dist: ta (>=0.11.0,<0.12.0)
30
- Requires-Dist: torch (>=2.1.2,<3.0.0) ; extra == "ml"
28
+ Requires-Dist: torch (>=2.1.2,<3.0.0)
31
29
  Requires-Dist: websocket-client (>=1.7.0,<2.0.0)
32
30
  Project-URL: Documentation, https://pfund.ai/docs
33
31
  Project-URL: Repository, https://github.com/PFund-Software-Ltd/pfund
@@ -35,6 +33,7 @@ Description-Content-Type: text/markdown
35
33
 
36
34
  # PFund: Algo-Trading Framework for Machine Learning, TradFi, CeFi and DeFi ready.
37
35
 
36
+ [![Jupyter Book Badge](docs/images/jupyterbook.svg)](https://jupyterbook.org)
38
37
  [![Poetry](https://img.shields.io/endpoint?url=https://python-poetry.org/badge/v0.json)](https://python-poetry.org/)
39
38
  [![PyPI](https://img.shields.io/pypi/v/pfund.svg)](https://pypi.org/project/pfund)
40
39
  ![PyPI - Support Python Versions](https://img.shields.io/pypi/pyversions/pfund)
@@ -108,7 +107,7 @@ This overview already omits some intricate steps, such as data handling and API
108
107
  - [x] Supports machine learning models, features, technical analysis indicators
109
108
  - [x] Both Strategy() and Model() are treated as first-class citizens
110
109
  - [x] Offers LEGO-style strategy and model building, allowing strategies to add other strategies, models to add other models
111
- - [x] Standardizes the algo-trading flow, from vectorized backtesting for strategy prototyping and event-driven backtesting for strategy development, to live trading for strategy deployment
110
+ - [x] Streamlines the algo-trading flow, from vectorized backtesting for strategy prototyping and event-driven backtesting for strategy development, to live trading for strategy deployment
112
111
  - [x] Enables parallel data processing, e.g. Interactive Brokers and Binance each have their own process for receiving data feeds
113
112
  - [ ] Allows choosing your preferred data tool, e.g. pandas, polars, pyspark etc.
114
113
  - [ ] Features a modern frontend using [Mantine UI](https://ui.mantine.dev/) and TradingView's Charts library
@@ -117,28 +116,16 @@ This overview already omits some intricate steps, such as data handling and API
117
116
 
118
117
  ## Installation
119
118
  ### Using [Poetry](https://python-poetry.org) (Recommended)
120
- > If you don't have poetry installed, please visit https://python-poetry.org/docs/
121
119
  ```bash
122
120
  poetry add pfund
123
121
  ```
124
122
 
125
- > To include the machine learning dependencies: \
126
- (Note that pytorch is not available in python 3.12)
127
- ```bash
128
- poetry add pfund[ml]
129
- ```
130
123
 
131
124
  ### Using Pip
132
125
  ```bash
133
126
  pip install pfund
134
127
  ```
135
128
 
136
- > To include the machine learning dependencies: \
137
- (Note that pytorch is not available in python 3.12)
138
- ```bash
139
- pip install pfund[ml]
140
- ```
141
-
142
129
 
143
130
  ## Quick Start
144
131
  ### Backtesting
@@ -1,5 +1,6 @@
1
1
  # PFund: Algo-Trading Framework for Machine Learning, TradFi, CeFi and DeFi ready.
2
2
 
3
+ [![Jupyter Book Badge](docs/images/jupyterbook.svg)](https://jupyterbook.org)
3
4
  [![Poetry](https://img.shields.io/endpoint?url=https://python-poetry.org/badge/v0.json)](https://python-poetry.org/)
4
5
  [![PyPI](https://img.shields.io/pypi/v/pfund.svg)](https://pypi.org/project/pfund)
5
6
  ![PyPI - Support Python Versions](https://img.shields.io/pypi/pyversions/pfund)
@@ -73,7 +74,7 @@ This overview already omits some intricate steps, such as data handling and API
73
74
  - [x] Supports machine learning models, features, technical analysis indicators
74
75
  - [x] Both Strategy() and Model() are treated as first-class citizens
75
76
  - [x] Offers LEGO-style strategy and model building, allowing strategies to add other strategies, models to add other models
76
- - [x] Standardizes the algo-trading flow, from vectorized backtesting for strategy prototyping and event-driven backtesting for strategy development, to live trading for strategy deployment
77
+ - [x] Streamlines the algo-trading flow, from vectorized backtesting for strategy prototyping and event-driven backtesting for strategy development, to live trading for strategy deployment
77
78
  - [x] Enables parallel data processing, e.g. Interactive Brokers and Binance each have their own process for receiving data feeds
78
79
  - [ ] Allows choosing your preferred data tool, e.g. pandas, polars, pyspark etc.
79
80
  - [ ] Features a modern frontend using [Mantine UI](https://ui.mantine.dev/) and TradingView's Charts library
@@ -82,28 +83,16 @@ This overview already omits some intricate steps, such as data handling and API
82
83
 
83
84
  ## Installation
84
85
  ### Using [Poetry](https://python-poetry.org) (Recommended)
85
- > If you don't have poetry installed, please visit https://python-poetry.org/docs/
86
86
  ```bash
87
87
  poetry add pfund
88
88
  ```
89
89
 
90
- > To include the machine learning dependencies: \
91
- (Note that pytorch is not available in python 3.12)
92
- ```bash
93
- poetry add pfund[ml]
94
- ```
95
90
 
96
91
  ### Using Pip
97
92
  ```bash
98
93
  pip install pfund
99
94
  ```
100
95
 
101
- > To include the machine learning dependencies: \
102
- (Note that pytorch is not available in python 3.12)
103
- ```bash
104
- pip install pfund[ml]
105
- ```
106
-
107
96
 
108
97
  ## Quick Start
109
98
  ### Backtesting
@@ -1,9 +1,18 @@
1
+ from importlib.metadata import version
2
+
1
3
  from pfund.config_handler import configure
2
4
  from pfund.engines import BacktestEngine, TrainEngine, TestEngine, TradeEngine
3
5
  from pfund.strategies import Strategy
4
- from pfund.models import Feature, Model, PyTorchModel, SKLearnModel
6
+ from pfund.models import Feature, Model
7
+ try:
8
+ from pfund.models import PyTorchModel
9
+ except ImportError:
10
+ pass
11
+ try:
12
+ from pfund.models import SKLearnModel
13
+ except ImportError:
14
+ pass
5
15
  from pfund.indicators import TAIndicator, TALibIndicator
6
- from importlib.metadata import version
7
16
 
8
17
 
9
18
  __version__ = version('pfund')
@@ -15,4 +24,4 @@ __all__ = (
15
24
  'BacktestEngine', 'TrainEngine', 'TestEngine', 'TradeEngine',
16
25
  'Strategy', 'Model', 'PyTorchModel', 'SKLearnModel',
17
26
  'Feature', 'TAIndicator', 'TALibIndicator',
18
- )
27
+ )
@@ -0,0 +1,4 @@
1
+ from pfund.cli.main import pfund_group
2
+
3
+
4
+ __all__ = ["pfund_group"]
@@ -0,0 +1,64 @@
1
+ import os
2
+ import yaml
3
+ from pathlib import Path
4
+ from pprint import pformat
5
+
6
+ import click
7
+
8
+ from pfund.const.paths import USER_CONFIG_FILE_PATH
9
+ from pfund.config_handler import ConfigHandler
10
+
11
+
12
+ def save_config(config: ConfigHandler, config_file_path: str | Path):
13
+ with open(config_file_path, 'w') as f:
14
+ yaml.dump(config.__dict__, f, default_flow_style=False)
15
+
16
+
17
+ def remove_config(config_file_path: str | Path):
18
+ config_file_path = Path(config_file_path)
19
+ if config_file_path.is_file():
20
+ os.remove(config_file_path)
21
+
22
+
23
+ @click.command()
24
+ @click.pass_context
25
+ @click.option('--data-path', type=click.Path(resolve_path=True), help='Set the data path for storing strategies, models, features and indicators')
26
+ @click.option('--log-path', type=click.Path(resolve_path=True), help='Set the log path')
27
+ @click.option('--logging-file', 'logging_config_file_path', type=click.Path(resolve_path=True, exists=True), help='Set the logging config file path')
28
+ @click.option('--logging-config', type=dict, help='Set the logging config')
29
+ @click.option('--use-fork-process', type=bool, help='If True, multiprocessing.set_start_method("fork")')
30
+ @click.option('--use-custom-excepthook', type=bool, help='If True, log uncaught exceptions to file')
31
+ @click.option('--list', '-l', is_flag=True, is_eager=True, help='List all available options')
32
+ @click.option('--reset', is_flag=True, is_eager=True, help='Reset the configuration to defaults')
33
+ def config(ctx, **kwargs):
34
+ """Configures pfund settings."""
35
+ config: ConfigHandler = ctx.obj['config']
36
+
37
+ # Filter out options that were not provided by the user
38
+ provided_options = {k: v for k, v in kwargs.items() if v is not None and v is not False}
39
+
40
+ if kwargs.get('list'): # Check if --list was used
41
+ del provided_options['list']
42
+ assert not provided_options, "No options should be provided with --list"
43
+ config_dict = config.__dict__
44
+ config_dict.update({'config_file_path': USER_CONFIG_FILE_PATH})
45
+ click.echo(f"PFund's config:\n{pformat(config_dict)}")
46
+ return
47
+
48
+ if kwargs.get('reset'): # Check if --reset was used
49
+ del provided_options['reset']
50
+ assert not provided_options, "No options should be provided with --reset"
51
+ remove_config(USER_CONFIG_FILE_PATH)
52
+ click.echo("PFund's config successfully reset.")
53
+ return
54
+
55
+ # prints out current config if no options are provided
56
+ if not provided_options:
57
+ raise click.UsageError("No options provided. Use --list to see all available options.")
58
+ else:
59
+ for option, value in provided_options.items():
60
+ setattr(config, option, value)
61
+ click.echo(f"{option} set to: {value}")
62
+
63
+ save_config(config, USER_CONFIG_FILE_PATH)
64
+ click.echo(f"config saved to {USER_CONFIG_FILE_PATH}.")
@@ -0,0 +1,30 @@
1
+ from pathlib import Path
2
+ import importlib.resources
3
+ import subprocess
4
+
5
+ from dotenv import find_dotenv, load_dotenv
6
+ import click
7
+
8
+ from pfund.const.paths import PROJ_NAME
9
+
10
+
11
+ @click.command(context_settings=dict(
12
+ ignore_unknown_options=True,
13
+ allow_extra_args=True,
14
+ ))
15
+ @click.pass_context
16
+ @click.option('--env-file', 'env_file_path', type=click.Path(exists=True), help='Path to the .env file')
17
+ @click.option('--docker-file', 'docker_file_path', type=click.Path(exists=True), help='Path to the docker-compose.yml file')
18
+ def docker_compose(ctx, env_file_path, docker_file_path):
19
+ """Forwards commands to docker-compose with the package's docker-compose.yml file if not specified."""
20
+ if not env_file_path:
21
+ env_file_path = find_dotenv(usecwd=True, raise_error_if_not_found=True)
22
+ click.echo(f'.env file path is not specified, using env file in "{env_file_path}"')
23
+ load_dotenv(env_file_path, override=True)
24
+ if not docker_file_path:
25
+ package_dir = Path(importlib.resources.files(PROJ_NAME)).resolve().parents[0]
26
+ docker_file_path = package_dir / 'docker-compose.yml'
27
+ else:
28
+ click.echo(f'loaded custom docker-compose.yml file from "{docker_file_path}"')
29
+ command = ['docker-compose', '-f', str(docker_file_path)] + ctx.args
30
+ subprocess.run(command)
@@ -0,0 +1,18 @@
1
+ import click
2
+
3
+ from pfund.config_handler import ConfigHandler
4
+ from pfund.cli.commands.docker_compose import docker_compose
5
+ from pfund.cli.commands.config import config
6
+
7
+
8
+ @click.group(context_settings={"help_option_names": ["-h", "--help"]})
9
+ @click.pass_context
10
+ @click.version_option()
11
+ def pfund_group(ctx):
12
+ """pfund's CLI"""
13
+ ctx.ensure_object(dict)
14
+ ctx.obj['config'] = ConfigHandler.load_config()
15
+
16
+
17
+ pfund_group.add_command(docker_compose)
18
+ pfund_group.add_command(config)
@@ -26,14 +26,14 @@ class Configuration:
26
26
  def read_config(self, config_name):
27
27
  global has_printed
28
28
  file_path = f'{self.config_path}/{config_name}.yml'
29
- short_file_path = short_path(file_path)
29
+ # short_file_path = short_path(file_path)
30
30
  if not os.path.exists(file_path):
31
- print(f'cannot find config {short_file_path}')
31
+ print(f'cannot find config {file_path}')
32
32
  else:
33
33
  with open(file_path, 'r') as f:
34
34
  if not has_printed:
35
35
  has_printed = True
36
- print(f'loaded config {short_file_path}')
36
+ print(f'loaded config {file_path}')
37
37
  return list(yaml.safe_load_all(f))
38
38
 
39
39
  def write_config(self, config_name, content):
@@ -6,13 +6,14 @@ import logging
6
6
  from types import TracebackType
7
7
  from dataclasses import dataclass
8
8
 
9
+ import yaml
9
10
  # from rich.traceback import install
10
11
 
11
- from pfund.const.paths import PROJ_NAME, PROJ_PATH, LOG_PATH, PROJ_CONFIG_PATH, STRATEGY_PATH, MODEL_PATH, FEATURE_PATH, INDICATOR_PATH
12
+ from pfund.const.paths import PROJ_NAME, PROJ_PATH, LOG_PATH, PROJ_CONFIG_PATH, DATA_PATH, USER_CONFIG_FILE_PATH
13
+
12
14
  # add python path so that for files like "ibapi" (official python code from IB)
13
15
  # can find their modules
14
16
  sys.path.append(f'{PROJ_PATH}/externals')
15
-
16
17
  # install(show_locals=False) # rich will set its own sys.excepthook
17
18
  # rich_excepthook = sys.excepthook # get rich's excepthook
18
19
 
@@ -50,18 +51,29 @@ def import_strategies_models_features_or_indicators(path: str):
50
51
 
51
52
  @dataclass
52
53
  class ConfigHandler:
53
- strategy_path: str = str(STRATEGY_PATH)
54
- model_path: str = str(MODEL_PATH)
55
- feature_path: str = str(FEATURE_PATH)
56
- indicator_path: str = str(INDICATOR_PATH)
54
+ data_path: str = str(DATA_PATH)
57
55
  log_path: str = str(LOG_PATH)
58
56
  logging_config_file_path: str = f'{PROJ_CONFIG_PATH}/logging.yml'
59
57
  logging_config: dict | None = None
60
58
  use_fork_process: bool = True
61
59
  use_custom_excepthook: bool = True
62
60
 
61
+ @classmethod
62
+ def load_config(cls):
63
+ config_file_path = USER_CONFIG_FILE_PATH
64
+ if config_file_path.is_file():
65
+ with open(config_file_path, 'r') as f:
66
+ config = yaml.safe_load(f) or {}
67
+ else:
68
+ config = {}
69
+ return cls(**config)
70
+
63
71
  def __post_init__(self):
64
- for path in (self.strategy_path, self.model_path, self.feature_path, self.indicator_path):
72
+ self.logging_config = self.logging_config or {}
73
+
74
+ strategy_path, model_path = f'{self.data_path}/strategies', f'{self.data_path}/models'
75
+ feature_path, indicator_path = f'{self.data_path}/features', f'{self.data_path}/indicators'
76
+ for path in [strategy_path, model_path, feature_path, indicator_path]:
65
77
  if not os.path.exists(path):
66
78
  os.makedirs(path)
67
79
  print(f'created {path}')
@@ -73,13 +85,10 @@ class ConfigHandler:
73
85
 
74
86
  if self.use_custom_excepthook:
75
87
  sys.excepthook = _custom_excepthook
76
-
88
+
77
89
 
78
90
  def configure(
79
- strategy_path: str = str(STRATEGY_PATH),
80
- model_path: str = str(MODEL_PATH),
81
- feature_path: str = str(FEATURE_PATH),
82
- indicator_path: str = str(INDICATOR_PATH),
91
+ data_path: str = str(DATA_PATH),
83
92
  log_path: str = str(LOG_PATH),
84
93
  logging_config_file_path: str = f'{PROJ_CONFIG_PATH}/logging.yml',
85
94
  logging_config: dict | None=None,
@@ -87,10 +96,7 @@ def configure(
87
96
  use_custom_excepthook: bool=True,
88
97
  ):
89
98
  return ConfigHandler(
90
- strategy_path=strategy_path,
91
- model_path=model_path,
92
- feature_path=feature_path,
93
- indicator_path=indicator_path,
99
+ data_path=data_path,
94
100
  log_path=log_path,
95
101
  logging_config_file_path=logging_config_file_path,
96
102
  logging_config=logging_config,
@@ -13,6 +13,7 @@ PROJ_CONFIG_PATH = PROJ_PATH / 'config'
13
13
  # user paths
14
14
  LOG_PATH = Path(user_log_dir()) / PROJ_NAME
15
15
  USER_CONFIG_PATH = Path(user_config_dir()) / PROJ_NAME
16
+ USER_CONFIG_FILE_PATH = USER_CONFIG_PATH / f'{PROJ_NAME}_config.yml'
16
17
  DATA_PATH = Path(user_data_dir()) / PROJ_NAME
17
18
  STRATEGY_PATH = DATA_PATH / 'strategies'
18
19
  MODEL_PATH = DATA_PATH / 'models'
@@ -79,8 +79,7 @@ class BacktestEngine(BaseEngine):
79
79
  continue
80
80
  if not hasattr(strategy, 'backtest'):
81
81
  raise Exception(f'Strategy {strat} does not have backtest() method, cannot run vectorized backtesting')
82
- df = strategy.get_df()
83
- strategy.backtest(df.copy(deep=True))
82
+ strategy.backtest()
84
83
  elif self.mode == 'event_driven':
85
84
  for strat, strategy in self.strategy_manager.strategies.items():
86
85
  if strat == '_dummy':
@@ -12,6 +12,7 @@ from pfund.managers.strategy_manager import StrategyManager
12
12
  from pfund.const.commons import *
13
13
  from pfund.config_handler import ConfigHandler
14
14
  from pfund.plogging import set_up_loggers
15
+ from pfund.plogging.config import LoggingDictConfigurator
15
16
 
16
17
 
17
18
  ENV_COLORS = {
@@ -43,10 +44,10 @@ class BaseEngine(Singleton):
43
44
  if not hasattr(cls, 'settings'):
44
45
  cls.settings = settings
45
46
  if not hasattr(cls, 'config'):
46
- cls.config = config if config else ConfigHandler()
47
+ cls.config = config if config else ConfigHandler.load_config()
47
48
  log_path = f'{cls.config.log_path}/{cls.env}'
48
49
  logging_config_file_path = cls.config.logging_config_file_path
49
- set_up_loggers(log_path, logging_config_file_path, user_logging_config=cls.config.logging_config)
50
+ cls.logging_configurator: LoggingDictConfigurator = set_up_loggers(log_path, logging_config_file_path, user_logging_config=cls.config.logging_config)
50
51
  return super().__new__(cls)
51
52
 
52
53
  def __init__(self, env, data_tool: DataTool='pandas', config: ConfigHandler | None=None, **settings):
@@ -26,7 +26,7 @@ class Exchange(BaseExchange):
26
26
  super().__init__(env, 'BYBIT')
27
27
 
28
28
  @staticmethod
29
- def categorize_product(ptype):
29
+ def categorize_product_type(ptype):
30
30
  is_spot = (ptype == 'SPOT')
31
31
  is_inverse = (ptype in ['IPERP', 'IFUT'])
32
32
  is_linear = not is_inverse and not is_spot
@@ -57,7 +57,7 @@ class BaseExchange:
57
57
  self.categories.append(category)
58
58
 
59
59
  def create_product(self, bccy, qccy, ptype, *args, **kwargs) -> CryptoProduct:
60
- if category := self.categorize_product(ptype) if hasattr(self, 'categorize_product') else '':
60
+ if category := self.categorize_product_type(ptype) if hasattr(self, 'categorize_product_type') else '':
61
61
  self.add_category(category)
62
62
  product = CryptoProduct(self.exch, bccy, qccy, ptype, *args, category=category, **kwargs)
63
63
  product.load_configs(self.configs)
@@ -0,0 +1,10 @@
1
+ from pfund.cli import pfund_group
2
+
3
+
4
+ def run_cli() -> None:
5
+ """Application Entrypoint."""
6
+ pfund_group(obj={})
7
+
8
+
9
+ if __name__ == '__main__':
10
+ run_cli()
@@ -12,7 +12,6 @@ if TYPE_CHECKING:
12
12
 
13
13
  from pfund.managers.data_manager import get_resolutions_from_kwargs
14
14
  from pfund.models.model_backtest import BacktestModel
15
- from pfund.strategies.strategy_base import BaseStrategy
16
15
  from pfund.models.model_base import BaseModel
17
16
 
18
17
 
@@ -25,7 +24,7 @@ class BacktestMixin:
25
24
  backtest_kwargs, train_kwargs = backtest or {}, train or {}
26
25
 
27
26
  if backtest_kwargs:
28
- data_source = self._get_data_source(backtest_kwargs)
27
+ data_source = self._get_data_source(trading_venue, backtest_kwargs)
29
28
  feed = self.get_feed(data_source)
30
29
  kwargs = self._prepare_kwargs(feed, kwargs)
31
30
 
@@ -45,11 +44,15 @@ class BacktestMixin:
45
44
  model = BacktestModel(type(model), model.ml_model, *model._args, **model._kwargs)
46
45
  return super().add_model(model, name=name, model_path=model_path, is_load=is_load)
47
46
 
48
- def _get_data_source(self, backtest_kwargs: dict):
47
+ def _get_data_source(self, trading_venue: str, backtest_kwargs: dict):
49
48
  from pfeed.const.commons import SUPPORTED_DATA_FEEDS
49
+ trading_venue = trading_venue.upper()
50
+ # if data_source is not defined, use trading_venue as data_source
51
+ if trading_venue in SUPPORTED_DATA_FEEDS and 'data_source' not in backtest_kwargs:
52
+ backtest_kwargs['data_source'] = trading_venue
50
53
  assert 'data_source' in backtest_kwargs, f"data_source must be defined"
51
54
  data_source = backtest_kwargs['data_source'].upper()
52
- assert backtest_kwargs['data_source'] in SUPPORTED_DATA_FEEDS, f"{data_source=} not in {SUPPORTED_DATA_FEEDS}"
55
+ assert data_source in SUPPORTED_DATA_FEEDS, f"{data_source=} not in {SUPPORTED_DATA_FEEDS}"
53
56
  return data_source
54
57
 
55
58
  def _prepare_kwargs(self, feed: BaseFeed, kwargs: dict):
@@ -99,10 +102,12 @@ class BacktestMixin:
99
102
 
100
103
  @staticmethod
101
104
  def get_feed(data_source: str) -> BaseFeed:
102
- import pfeed as dd
105
+ from pfeed.feeds import YahooFinanceFeed, BybitFeed
103
106
  data_source = data_source.upper()
104
107
  if data_source == 'YAHOO_FINANCE':
105
- feed = dd.YahooFinanceFeed()
108
+ feed = YahooFinanceFeed()
109
+ elif data_source == 'BYBIT':
110
+ feed = BybitFeed()
106
111
  # TODO: other feeds
107
112
  else:
108
113
  raise NotImplementedError
@@ -123,9 +128,9 @@ class BacktestMixin:
123
128
  continue
124
129
  product = data.product
125
130
  resolution = data.resolution
126
- symbol = product.symbol
127
- df = feed.get_historical_data(symbol, rollback_period=rollback_period, start_date=start_date, end_date=end_date, resolution=repr(resolution), **backtest_kwargs)
128
- assert not df.empty, f"dataframe is empty for {symbol=}"
131
+ pdt_or_symbol = product.symbol if feed.name == 'YAHOO_FINANCE' else product.pdt
132
+ df = feed.get_historical_data(pdt_or_symbol, rollback_period=rollback_period, start_date=start_date, end_date=end_date, resolution=repr(resolution), **backtest_kwargs)
133
+ assert not df.empty, f"dataframe is empty for {pdt_or_symbol=}"
129
134
  df.reset_index(inplace=True)
130
135
  latest_date = str(df['ts'][0])
131
136
  if feed.name == 'YAHOO_FINANCE' and latest_date == utcnow_date:
@@ -0,0 +1,6 @@
1
+ from pfund.models.model_base import BaseModel, BaseModel as Model, BaseFeature as Feature
2
+ try:
3
+ from pfund.models.pytorch_model import PyTorchModel
4
+ from pfund.models.sklearn_model import SKLearnModel
5
+ except ImportError:
6
+ pass
@@ -8,13 +8,16 @@ from collections import defaultdict
8
8
 
9
9
  from typing import TYPE_CHECKING, Any, Union
10
10
 
11
- import joblib
12
- import torch
11
+ try:
12
+ import joblib
13
+ import torch
14
+ import torch.nn as nn
15
+ from sklearn.base import BaseEstimator, ClassifierMixin, RegressorMixin
16
+ from sklearn.pipeline import Pipeline
17
+ except ImportError:
18
+ pass
13
19
  import numpy as np
14
20
  import pandas as pd
15
- import torch.nn as nn
16
- from sklearn.base import BaseEstimator, ClassifierMixin, RegressorMixin
17
- from sklearn.pipeline import Pipeline
18
21
 
19
22
  if TYPE_CHECKING:
20
23
  from pfund.strategies.strategy_base import BaseStrategy
@@ -1,11 +1,10 @@
1
1
  import os
2
2
  import logging
3
- from pathlib import Path
4
3
 
5
4
  from typing import Literal
6
5
 
7
6
  from pfund.plogging.config import LoggingDictConfigurator
8
- from pfund.utils.utils import load_yaml_file
7
+ from pfund.utils.utils import load_yaml_file, get_engine_class
9
8
 
10
9
 
11
10
  def print_all_loggers():
@@ -14,7 +13,7 @@ def print_all_loggers():
14
13
  print(name, logger, logger.handlers)
15
14
 
16
15
 
17
- def set_up_loggers(log_path, logging_config_file_path, user_logging_config: dict | None=None):
16
+ def set_up_loggers(log_path, logging_config_file_path, user_logging_config: dict | None=None) -> LoggingDictConfigurator:
18
17
  def deep_update(default_dict, override_dict, raise_if_key_not_exist=False):
19
18
  '''Updates a default dictionary with an override dictionary, supports nested dictionaries.'''
20
19
  for key, value in override_dict.items():
@@ -33,9 +32,8 @@ def set_up_loggers(log_path, logging_config_file_path, user_logging_config: dict
33
32
  else:
34
33
  # Update the key with the override value
35
34
  default_dict[key] = value
36
- print('Setting up loggers...')
37
- log_path, logging_config_file_path = Path(log_path), Path(logging_config_file_path)
38
- if not log_path.exists():
35
+ # print('Setting up loggers...')
36
+ if not os.path.exists(log_path):
39
37
  os.makedirs(log_path)
40
38
  print(f'created {str(log_path)}')
41
39
  logging_config: dict = load_yaml_file(logging_config_file_path)
@@ -43,8 +41,10 @@ def set_up_loggers(log_path, logging_config_file_path, user_logging_config: dict
43
41
  deep_update(logging_config, user_logging_config)
44
42
  logging_config['log_path'] = log_path
45
43
  # ≈ logging.config.dictConfig(logging_config) with a custom configurator
46
- LoggingDictConfigurator(logging_config).configure()
47
-
44
+ logging_configurator = LoggingDictConfigurator(logging_config)
45
+ logging_configurator.configure()
46
+ return logging_configurator
47
+
48
48
 
49
49
  # TODO: support 'feature', 'indicator'
50
50
  def create_dynamic_logger(name: str, type_: Literal['strategy', 'model', 'manager']):
@@ -57,8 +57,8 @@ def create_dynamic_logger(name: str, type_: Literal['strategy', 'model', 'manage
57
57
  assert name, "logger name cannot be empty/None"
58
58
  assert type_ in ['strategy', 'model', 'manager'], f"Unsupported {type_=}"
59
59
 
60
- # NOTE: LoggingDictConfigurator is a singleton, since it has already configured in set_up_loggers(), no need to pass in config to it
61
- config = LoggingDictConfigurator(config=None)
60
+ Engine = get_engine_class()
61
+ config = Engine.logging_configurator
62
62
 
63
63
  logging_config = config.config_orig
64
64
  loggers_config = logging_config['loggers']
@@ -4,7 +4,6 @@ import copy
4
4
  import logging
5
5
  from logging.config import DictConfigurator
6
6
 
7
- from pfund.utils.utils import Singleton
8
7
  from pfund.plogging.filters import FullPathFilter
9
8
  from pfund.plogging.formatter import ColoredFormatter
10
9
 
@@ -19,7 +18,7 @@ LEVELS = {
19
18
 
20
19
 
21
20
  # override logging's DictConfigurator as it doesn't pass in logger names to file handlers to create filenames
22
- class LoggingDictConfigurator(Singleton, DictConfigurator):
21
+ class LoggingDictConfigurator(DictConfigurator):
23
22
  _MANUALLY_CONFIGURED_HANDLERS = [
24
23
  'file_handler',
25
24
  'compressed_timed_rotating_file_handler',