tigeropen 3.5.9__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (468) hide show
  1. build/lib/dist/tigeropen-3.5.8.tar.gz +0 -0
  2. build/lib/tigeropen/__init__.py +7 -0
  3. build/lib/tigeropen/cli/__init__.py +7 -0
  4. build/lib/tigeropen/cli/account_cmd.py +84 -0
  5. build/lib/tigeropen/cli/client_factory.py +79 -0
  6. build/lib/tigeropen/cli/config_cmd.py +129 -0
  7. build/lib/tigeropen/cli/formatting.py +117 -0
  8. build/lib/tigeropen/cli/main.py +197 -0
  9. build/lib/tigeropen/cli/push_cmd.py +118 -0
  10. build/lib/tigeropen/cli/quote_cmd.py +599 -0
  11. build/lib/tigeropen/cli/trade_cmd.py +226 -0
  12. build/lib/tigeropen/common/__init__.py +6 -0
  13. build/lib/tigeropen/common/consts/__init__.py +279 -0
  14. build/lib/tigeropen/common/consts/filter_fields.py +471 -0
  15. build/lib/tigeropen/common/consts/fundamental_fields.py +850 -0
  16. build/lib/tigeropen/common/consts/params.py +30 -0
  17. build/lib/tigeropen/common/consts/push_destinations.py +12 -0
  18. build/lib/tigeropen/common/consts/push_subscriptions.py +13 -0
  19. build/lib/tigeropen/common/consts/push_types.py +66 -0
  20. build/lib/tigeropen/common/consts/quote_keys.py +29 -0
  21. build/lib/tigeropen/common/consts/service_types.py +136 -0
  22. build/lib/tigeropen/common/consts/tick_constants.py +94 -0
  23. build/lib/tigeropen/common/exceptions.py +25 -0
  24. build/lib/tigeropen/common/model.py +36 -0
  25. build/lib/tigeropen/common/request.py +32 -0
  26. build/lib/tigeropen/common/response.py +28 -0
  27. build/lib/tigeropen/common/util/__init__.py +6 -0
  28. build/lib/tigeropen/common/util/account_util.py +17 -0
  29. build/lib/tigeropen/common/util/common_utils.py +53 -0
  30. build/lib/tigeropen/common/util/contract_utils.py +110 -0
  31. build/lib/tigeropen/common/util/order_utils.py +242 -0
  32. build/lib/tigeropen/common/util/price_util.py +90 -0
  33. build/lib/tigeropen/common/util/signature_utils.py +107 -0
  34. build/lib/tigeropen/common/util/string_utils.py +33 -0
  35. build/lib/tigeropen/common/util/tick_util.py +27 -0
  36. build/lib/tigeropen/common/util/web_utils.py +39 -0
  37. build/lib/tigeropen/examples/__init__.py +6 -0
  38. build/lib/tigeropen/examples/ai/mcp_server/MANIFEST.in +2 -0
  39. build/lib/tigeropen/examples/ai/mcp_server/README.md +84 -0
  40. build/lib/tigeropen/examples/ai/mcp_server/__init__.py +3 -0
  41. build/lib/tigeropen/examples/ai/mcp_server/dist/tigermcp-0.1.7.tar.gz +0 -0
  42. build/lib/tigeropen/examples/ai/mcp_server/setup.py +35 -0
  43. build/lib/tigeropen/examples/ai/mcp_server/tigermcp/__init__.py +3 -0
  44. build/lib/tigeropen/examples/ai/mcp_server/tigermcp/server.py +1264 -0
  45. build/lib/tigeropen/examples/ai/mcp_server/tigermcp/version.py +1 -0
  46. build/lib/tigeropen/examples/client_config.py +25 -0
  47. build/lib/tigeropen/examples/financial_demo.py +135 -0
  48. build/lib/tigeropen/examples/nasdaq100.py +309 -0
  49. build/lib/tigeropen/examples/option_helpers/__init__.py +4 -0
  50. build/lib/tigeropen/examples/option_helpers/extra_calculator.py +58 -0
  51. build/lib/tigeropen/examples/option_helpers/helpers.py +308 -0
  52. build/lib/tigeropen/examples/option_helpers/probability_calculator.py +270 -0
  53. build/lib/tigeropen/examples/option_helpers/util.py +589 -0
  54. build/lib/tigeropen/examples/push_client_demo.py +395 -0
  55. build/lib/tigeropen/examples/push_client_stomp_demo.py +270 -0
  56. build/lib/tigeropen/examples/quote_client_demo.py +323 -0
  57. build/lib/tigeropen/examples/trade_client_demo.py +228 -0
  58. build/lib/tigeropen/fundamental/__init__.py +1 -0
  59. build/lib/tigeropen/fundamental/domain/__init__.py +1 -0
  60. build/lib/tigeropen/fundamental/request/__init__.py +1 -0
  61. build/lib/tigeropen/fundamental/request/model.py +363 -0
  62. build/lib/tigeropen/fundamental/response/__init__.py +1 -0
  63. build/lib/tigeropen/fundamental/response/corporate_dividend_response.py +31 -0
  64. build/lib/tigeropen/fundamental/response/corporate_earnings_calendar_response.py +29 -0
  65. build/lib/tigeropen/fundamental/response/corporate_split_response.py +28 -0
  66. build/lib/tigeropen/fundamental/response/dataframe_response.py +27 -0
  67. build/lib/tigeropen/fundamental/response/financial_daily_response.py +28 -0
  68. build/lib/tigeropen/fundamental/response/financial_exchange_rate_response.py +29 -0
  69. build/lib/tigeropen/fundamental/response/financial_report_response.py +29 -0
  70. build/lib/tigeropen/fundamental/response/industry_response.py +62 -0
  71. build/lib/tigeropen/push/__init__.py +28 -0
  72. build/lib/tigeropen/push/network/__init__.py +0 -0
  73. build/lib/tigeropen/push/network/connect.py +85 -0
  74. build/lib/tigeropen/push/network/exception.py +26 -0
  75. build/lib/tigeropen/push/network/listener.py +229 -0
  76. build/lib/tigeropen/push/network/protocal.py +45 -0
  77. build/lib/tigeropen/push/network/transport.py +818 -0
  78. build/lib/tigeropen/push/network/utils.py +107 -0
  79. build/lib/tigeropen/push/pb/AssetData.proto +23 -0
  80. build/lib/tigeropen/push/pb/AssetData_pb2.py +36 -0
  81. build/lib/tigeropen/push/pb/AssetData_pb2.pyi +35 -0
  82. build/lib/tigeropen/push/pb/KlineData.proto +16 -0
  83. build/lib/tigeropen/push/pb/KlineData_pb2.py +36 -0
  84. build/lib/tigeropen/push/pb/KlineData_pb2.pyi +31 -0
  85. build/lib/tigeropen/push/pb/OptionTopData.proto +40 -0
  86. build/lib/tigeropen/push/pb/OptionTopData_pb2.py +42 -0
  87. build/lib/tigeropen/push/pb/OptionTopData_pb2.pyi +69 -0
  88. build/lib/tigeropen/push/pb/OrderStatusData.proto +51 -0
  89. build/lib/tigeropen/push/pb/OrderStatusData_pb2.py +36 -0
  90. build/lib/tigeropen/push/pb/OrderStatusData_pb2.pyi +96 -0
  91. build/lib/tigeropen/push/pb/OrderTransactionData.proto +24 -0
  92. build/lib/tigeropen/push/pb/OrderTransactionData_pb2.py +36 -0
  93. build/lib/tigeropen/push/pb/OrderTransactionData_pb2.pyi +43 -0
  94. build/lib/tigeropen/push/pb/PositionData.proto +29 -0
  95. build/lib/tigeropen/push/pb/PositionData_pb2.py +36 -0
  96. build/lib/tigeropen/push/pb/PositionData_pb2.pyi +53 -0
  97. build/lib/tigeropen/push/pb/PushData.proto +32 -0
  98. build/lib/tigeropen/push/pb/PushData_pb2.py +60 -0
  99. build/lib/tigeropen/push/pb/PushData_pb2.pyi +57 -0
  100. build/lib/tigeropen/push/pb/QuoteBBOData.proto +20 -0
  101. build/lib/tigeropen/push/pb/QuoteBBOData_pb2.py +38 -0
  102. build/lib/tigeropen/push/pb/QuoteBBOData_pb2.pyi +29 -0
  103. build/lib/tigeropen/push/pb/QuoteBasicData.proto +38 -0
  104. build/lib/tigeropen/push/pb/QuoteBasicData_pb2.py +40 -0
  105. build/lib/tigeropen/push/pb/QuoteBasicData_pb2.pyi +57 -0
  106. build/lib/tigeropen/push/pb/QuoteData.proto +57 -0
  107. build/lib/tigeropen/push/pb/QuoteData_pb2.py +39 -0
  108. build/lib/tigeropen/push/pb/QuoteData_pb2.pyi +85 -0
  109. build/lib/tigeropen/push/pb/QuoteDepthData.proto +20 -0
  110. build/lib/tigeropen/push/pb/QuoteDepthData_pb2.py +38 -0
  111. build/lib/tigeropen/push/pb/QuoteDepthData_pb2.pyi +31 -0
  112. build/lib/tigeropen/push/pb/Request.proto +28 -0
  113. build/lib/tigeropen/push/pb/Request_pb2.py +42 -0
  114. build/lib/tigeropen/push/pb/Request_pb2.pyi +47 -0
  115. build/lib/tigeropen/push/pb/Response.proto +15 -0
  116. build/lib/tigeropen/push/pb/Response_pb2.py +88 -0
  117. build/lib/tigeropen/push/pb/Response_pb2.pyi +35 -0
  118. build/lib/tigeropen/push/pb/SocketCommon.proto +46 -0
  119. build/lib/tigeropen/push/pb/SocketCommon_pb2.py +42 -0
  120. build/lib/tigeropen/push/pb/SocketCommon_pb2.pyi +72 -0
  121. build/lib/tigeropen/push/pb/StockTopData.proto +20 -0
  122. build/lib/tigeropen/push/pb/StockTopData_pb2.py +40 -0
  123. build/lib/tigeropen/push/pb/StockTopData_pb2.pyi +32 -0
  124. build/lib/tigeropen/push/pb/TickData.proto +19 -0
  125. build/lib/tigeropen/push/pb/TickData_pb2.py +38 -0
  126. build/lib/tigeropen/push/pb/TickData_pb2.pyi +35 -0
  127. build/lib/tigeropen/push/pb/TradeTickData.proto +26 -0
  128. build/lib/tigeropen/push/pb/TradeTickData_pb2.py +38 -0
  129. build/lib/tigeropen/push/pb/TradeTickData_pb2.pyi +45 -0
  130. build/lib/tigeropen/push/pb/__init__.py +7 -0
  131. build/lib/tigeropen/push/pb/readme.md +5 -0
  132. build/lib/tigeropen/push/pb/trade_tick.py +28 -0
  133. build/lib/tigeropen/push/pb/util.py +251 -0
  134. build/lib/tigeropen/push/protobuf_push_client.py +556 -0
  135. build/lib/tigeropen/push/push_client.py +399 -0
  136. build/lib/tigeropen/push/stomp_push_client.py +609 -0
  137. build/lib/tigeropen/push/thread_pool.py +59 -0
  138. build/lib/tigeropen/quote/__init__.py +6 -0
  139. build/lib/tigeropen/quote/domain/__init__.py +6 -0
  140. build/lib/tigeropen/quote/domain/bar.py +22 -0
  141. build/lib/tigeropen/quote/domain/capital_distribution.py +19 -0
  142. build/lib/tigeropen/quote/domain/filter.py +243 -0
  143. build/lib/tigeropen/quote/domain/market_status.py +20 -0
  144. build/lib/tigeropen/quote/domain/option_analysis.py +51 -0
  145. build/lib/tigeropen/quote/domain/quote_brief.py +60 -0
  146. build/lib/tigeropen/quote/domain/stock_broker.py +33 -0
  147. build/lib/tigeropen/quote/domain/tick.py +18 -0
  148. build/lib/tigeropen/quote/domain/timeline.py +17 -0
  149. build/lib/tigeropen/quote/quote_client.py +3266 -0
  150. build/lib/tigeropen/quote/request/__init__.py +8 -0
  151. build/lib/tigeropen/quote/request/model.py +1614 -0
  152. build/lib/tigeropen/quote/response/__init__.py +6 -0
  153. build/lib/tigeropen/quote/response/broker_hold_response.py +23 -0
  154. build/lib/tigeropen/quote/response/capital_distribution_response.py +24 -0
  155. build/lib/tigeropen/quote/response/capital_flow_response.py +27 -0
  156. build/lib/tigeropen/quote/response/fund_contracts_response.py +28 -0
  157. build/lib/tigeropen/quote/response/future_briefs_response.py +36 -0
  158. build/lib/tigeropen/quote/response/future_contract_response.py +44 -0
  159. build/lib/tigeropen/quote/response/future_depth_response.py +31 -0
  160. build/lib/tigeropen/quote/response/future_exchange_response.py +37 -0
  161. build/lib/tigeropen/quote/response/future_history_main_contract_response.py +28 -0
  162. build/lib/tigeropen/quote/response/future_quote_bar_response.py +42 -0
  163. build/lib/tigeropen/quote/response/future_quote_ticks_response.py +25 -0
  164. build/lib/tigeropen/quote/response/future_trading_times_response.py +42 -0
  165. build/lib/tigeropen/quote/response/kline_quota_response.py +21 -0
  166. build/lib/tigeropen/quote/response/market_scanner_response.py +48 -0
  167. build/lib/tigeropen/quote/response/market_status_response.py +51 -0
  168. build/lib/tigeropen/quote/response/option_analysis_response.py +64 -0
  169. build/lib/tigeropen/quote/response/option_briefs_response.py +69 -0
  170. build/lib/tigeropen/quote/response/option_chains_response.py +42 -0
  171. build/lib/tigeropen/quote/response/option_depth_response.py +37 -0
  172. build/lib/tigeropen/quote/response/option_expirations_response.py +34 -0
  173. build/lib/tigeropen/quote/response/option_quote_bar_response.py +60 -0
  174. build/lib/tigeropen/quote/response/option_quote_ticks_response.py +54 -0
  175. build/lib/tigeropen/quote/response/option_symbols_response.py +25 -0
  176. build/lib/tigeropen/quote/response/option_timeline_response.py +57 -0
  177. build/lib/tigeropen/quote/response/quote_bar_response.py +36 -0
  178. build/lib/tigeropen/quote/response/quote_brief_response.py +53 -0
  179. build/lib/tigeropen/quote/response/quote_dataframe_response.py +35 -0
  180. build/lib/tigeropen/quote/response/quote_delay_briefs_response.py +28 -0
  181. build/lib/tigeropen/quote/response/quote_depth_response.py +31 -0
  182. build/lib/tigeropen/quote/response/quote_grab_permission_response.py +21 -0
  183. build/lib/tigeropen/quote/response/quote_hour_trading_timeline_response.py +66 -0
  184. build/lib/tigeropen/quote/response/quote_overnight_response.py +19 -0
  185. build/lib/tigeropen/quote/response/quote_ticks_response.py +66 -0
  186. build/lib/tigeropen/quote/response/quote_timeline_history_response.py +65 -0
  187. build/lib/tigeropen/quote/response/quote_timeline_response.py +81 -0
  188. build/lib/tigeropen/quote/response/stock_briefs_response.py +36 -0
  189. build/lib/tigeropen/quote/response/stock_broker_response.py +46 -0
  190. build/lib/tigeropen/quote/response/stock_details_response.py +135 -0
  191. build/lib/tigeropen/quote/response/stock_short_interest_response.py +43 -0
  192. build/lib/tigeropen/quote/response/stock_trade_meta_response.py +39 -0
  193. build/lib/tigeropen/quote/response/symbol_names_response.py +24 -0
  194. build/lib/tigeropen/quote/response/symbols_response.py +23 -0
  195. build/lib/tigeropen/quote/response/trade_rank_response.py +28 -0
  196. build/lib/tigeropen/quote/response/trading_calendar_response.py +21 -0
  197. build/lib/tigeropen/quote/response/warrant_briefs_response.py +24 -0
  198. build/lib/tigeropen/quote/response/warrant_filter_response.py +27 -0
  199. build/lib/tigeropen/tiger_open_client.py +278 -0
  200. build/lib/tigeropen/tiger_open_config.py +574 -0
  201. build/lib/tigeropen/trade/__init__.py +6 -0
  202. build/lib/tigeropen/trade/domain/__init__.py +6 -0
  203. build/lib/tigeropen/trade/domain/account.py +269 -0
  204. build/lib/tigeropen/trade/domain/contract.py +164 -0
  205. build/lib/tigeropen/trade/domain/option_exercise.py +94 -0
  206. build/lib/tigeropen/trade/domain/order.py +314 -0
  207. build/lib/tigeropen/trade/domain/position.py +78 -0
  208. build/lib/tigeropen/trade/domain/prime_account.py +149 -0
  209. build/lib/tigeropen/trade/domain/profile.py +20 -0
  210. build/lib/tigeropen/trade/domain/transfer.py +157 -0
  211. build/lib/tigeropen/trade/request/__init__.py +6 -0
  212. build/lib/tigeropen/trade/request/model.py +2162 -0
  213. build/lib/tigeropen/trade/response/__init__.py +14 -0
  214. build/lib/tigeropen/trade/response/account_profile_response.py +29 -0
  215. build/lib/tigeropen/trade/response/aggregate_assets_response.py +18 -0
  216. build/lib/tigeropen/trade/response/analytics_asset_response.py +29 -0
  217. build/lib/tigeropen/trade/response/assets_response.py +93 -0
  218. build/lib/tigeropen/trade/response/contracts_response.py +42 -0
  219. build/lib/tigeropen/trade/response/forex_order_response.py +20 -0
  220. build/lib/tigeropen/trade/response/fund_details_response.py +29 -0
  221. build/lib/tigeropen/trade/response/funding_history_response.py +30 -0
  222. build/lib/tigeropen/trade/response/option_exercise_response.py +98 -0
  223. build/lib/tigeropen/trade/response/order_id_response.py +43 -0
  224. build/lib/tigeropen/trade/response/order_preview_response.py +17 -0
  225. build/lib/tigeropen/trade/response/orders_response.py +163 -0
  226. build/lib/tigeropen/trade/response/positions_response.py +79 -0
  227. build/lib/tigeropen/trade/response/prime_assets_response.py +36 -0
  228. build/lib/tigeropen/trade/response/segment_fund_response.py +69 -0
  229. build/lib/tigeropen/trade/response/transactions_response.py +44 -0
  230. build/lib/tigeropen/trade/response/transfer_response.py +104 -0
  231. build/lib/tigeropen/trade/trade_client.py +1761 -0
  232. dist/tigeropen-3.5.8.tar.gz +0 -0
  233. dist/tigeropen-3.5.9.tar.gz +0 -0
  234. tigeropen/__init__.py +7 -0
  235. tigeropen/cli/__init__.py +7 -0
  236. tigeropen/cli/account_cmd.py +84 -0
  237. tigeropen/cli/client_factory.py +79 -0
  238. tigeropen/cli/config_cmd.py +129 -0
  239. tigeropen/cli/formatting.py +117 -0
  240. tigeropen/cli/main.py +197 -0
  241. tigeropen/cli/push_cmd.py +118 -0
  242. tigeropen/cli/quote_cmd.py +599 -0
  243. tigeropen/cli/trade_cmd.py +226 -0
  244. tigeropen/common/__init__.py +6 -0
  245. tigeropen/common/consts/__init__.py +279 -0
  246. tigeropen/common/consts/filter_fields.py +471 -0
  247. tigeropen/common/consts/fundamental_fields.py +850 -0
  248. tigeropen/common/consts/params.py +30 -0
  249. tigeropen/common/consts/push_destinations.py +12 -0
  250. tigeropen/common/consts/push_subscriptions.py +13 -0
  251. tigeropen/common/consts/push_types.py +66 -0
  252. tigeropen/common/consts/quote_keys.py +29 -0
  253. tigeropen/common/consts/service_types.py +136 -0
  254. tigeropen/common/consts/tick_constants.py +94 -0
  255. tigeropen/common/exceptions.py +25 -0
  256. tigeropen/common/model.py +36 -0
  257. tigeropen/common/request.py +32 -0
  258. tigeropen/common/response.py +28 -0
  259. tigeropen/common/util/__init__.py +6 -0
  260. tigeropen/common/util/account_util.py +17 -0
  261. tigeropen/common/util/common_utils.py +53 -0
  262. tigeropen/common/util/contract_utils.py +110 -0
  263. tigeropen/common/util/order_utils.py +242 -0
  264. tigeropen/common/util/price_util.py +90 -0
  265. tigeropen/common/util/signature_utils.py +107 -0
  266. tigeropen/common/util/string_utils.py +33 -0
  267. tigeropen/common/util/tick_util.py +27 -0
  268. tigeropen/common/util/web_utils.py +39 -0
  269. tigeropen/examples/__init__.py +6 -0
  270. tigeropen/examples/ai/mcp_server/MANIFEST.in +2 -0
  271. tigeropen/examples/ai/mcp_server/README.md +84 -0
  272. tigeropen/examples/ai/mcp_server/__init__.py +3 -0
  273. tigeropen/examples/ai/mcp_server/dist/tigermcp-0.1.7.tar.gz +0 -0
  274. tigeropen/examples/ai/mcp_server/setup.py +35 -0
  275. tigeropen/examples/ai/mcp_server/tigermcp/__init__.py +3 -0
  276. tigeropen/examples/ai/mcp_server/tigermcp/server.py +1264 -0
  277. tigeropen/examples/ai/mcp_server/tigermcp/version.py +1 -0
  278. tigeropen/examples/client_config.py +25 -0
  279. tigeropen/examples/financial_demo.py +135 -0
  280. tigeropen/examples/nasdaq100.py +309 -0
  281. tigeropen/examples/option_helpers/__init__.py +4 -0
  282. tigeropen/examples/option_helpers/extra_calculator.py +58 -0
  283. tigeropen/examples/option_helpers/helpers.py +308 -0
  284. tigeropen/examples/option_helpers/probability_calculator.py +270 -0
  285. tigeropen/examples/option_helpers/util.py +589 -0
  286. tigeropen/examples/push_client_demo.py +395 -0
  287. tigeropen/examples/push_client_stomp_demo.py +270 -0
  288. tigeropen/examples/quote_client_demo.py +323 -0
  289. tigeropen/examples/trade_client_demo.py +228 -0
  290. tigeropen/fundamental/__init__.py +1 -0
  291. tigeropen/fundamental/domain/__init__.py +1 -0
  292. tigeropen/fundamental/request/__init__.py +1 -0
  293. tigeropen/fundamental/request/model.py +363 -0
  294. tigeropen/fundamental/response/__init__.py +1 -0
  295. tigeropen/fundamental/response/corporate_dividend_response.py +31 -0
  296. tigeropen/fundamental/response/corporate_earnings_calendar_response.py +29 -0
  297. tigeropen/fundamental/response/corporate_split_response.py +28 -0
  298. tigeropen/fundamental/response/dataframe_response.py +27 -0
  299. tigeropen/fundamental/response/financial_daily_response.py +28 -0
  300. tigeropen/fundamental/response/financial_exchange_rate_response.py +29 -0
  301. tigeropen/fundamental/response/financial_report_response.py +29 -0
  302. tigeropen/fundamental/response/industry_response.py +62 -0
  303. tigeropen/push/__init__.py +28 -0
  304. tigeropen/push/network/__init__.py +0 -0
  305. tigeropen/push/network/connect.py +85 -0
  306. tigeropen/push/network/exception.py +26 -0
  307. tigeropen/push/network/listener.py +229 -0
  308. tigeropen/push/network/protocal.py +45 -0
  309. tigeropen/push/network/transport.py +818 -0
  310. tigeropen/push/network/utils.py +107 -0
  311. tigeropen/push/pb/AssetData.proto +23 -0
  312. tigeropen/push/pb/AssetData_pb2.py +36 -0
  313. tigeropen/push/pb/AssetData_pb2.pyi +35 -0
  314. tigeropen/push/pb/KlineData.proto +16 -0
  315. tigeropen/push/pb/KlineData_pb2.py +36 -0
  316. tigeropen/push/pb/KlineData_pb2.pyi +31 -0
  317. tigeropen/push/pb/OptionTopData.proto +40 -0
  318. tigeropen/push/pb/OptionTopData_pb2.py +42 -0
  319. tigeropen/push/pb/OptionTopData_pb2.pyi +69 -0
  320. tigeropen/push/pb/OrderStatusData.proto +53 -0
  321. tigeropen/push/pb/OrderStatusData_pb2.py +36 -0
  322. tigeropen/push/pb/OrderStatusData_pb2.pyi +100 -0
  323. tigeropen/push/pb/OrderTransactionData.proto +24 -0
  324. tigeropen/push/pb/OrderTransactionData_pb2.py +36 -0
  325. tigeropen/push/pb/OrderTransactionData_pb2.pyi +43 -0
  326. tigeropen/push/pb/PositionData.proto +29 -0
  327. tigeropen/push/pb/PositionData_pb2.py +36 -0
  328. tigeropen/push/pb/PositionData_pb2.pyi +53 -0
  329. tigeropen/push/pb/PushData.proto +32 -0
  330. tigeropen/push/pb/PushData_pb2.py +60 -0
  331. tigeropen/push/pb/PushData_pb2.pyi +57 -0
  332. tigeropen/push/pb/QuoteBBOData.proto +20 -0
  333. tigeropen/push/pb/QuoteBBOData_pb2.py +38 -0
  334. tigeropen/push/pb/QuoteBBOData_pb2.pyi +29 -0
  335. tigeropen/push/pb/QuoteBasicData.proto +38 -0
  336. tigeropen/push/pb/QuoteBasicData_pb2.py +40 -0
  337. tigeropen/push/pb/QuoteBasicData_pb2.pyi +57 -0
  338. tigeropen/push/pb/QuoteData.proto +57 -0
  339. tigeropen/push/pb/QuoteData_pb2.py +39 -0
  340. tigeropen/push/pb/QuoteData_pb2.pyi +85 -0
  341. tigeropen/push/pb/QuoteDepthData.proto +20 -0
  342. tigeropen/push/pb/QuoteDepthData_pb2.py +38 -0
  343. tigeropen/push/pb/QuoteDepthData_pb2.pyi +31 -0
  344. tigeropen/push/pb/Request.proto +28 -0
  345. tigeropen/push/pb/Request_pb2.py +42 -0
  346. tigeropen/push/pb/Request_pb2.pyi +47 -0
  347. tigeropen/push/pb/Response.proto +15 -0
  348. tigeropen/push/pb/Response_pb2.py +88 -0
  349. tigeropen/push/pb/Response_pb2.pyi +35 -0
  350. tigeropen/push/pb/SocketCommon.proto +46 -0
  351. tigeropen/push/pb/SocketCommon_pb2.py +42 -0
  352. tigeropen/push/pb/SocketCommon_pb2.pyi +72 -0
  353. tigeropen/push/pb/StockTopData.proto +20 -0
  354. tigeropen/push/pb/StockTopData_pb2.py +40 -0
  355. tigeropen/push/pb/StockTopData_pb2.pyi +32 -0
  356. tigeropen/push/pb/TickData.proto +19 -0
  357. tigeropen/push/pb/TickData_pb2.py +38 -0
  358. tigeropen/push/pb/TickData_pb2.pyi +35 -0
  359. tigeropen/push/pb/TradeTickData.proto +26 -0
  360. tigeropen/push/pb/TradeTickData_pb2.py +38 -0
  361. tigeropen/push/pb/TradeTickData_pb2.pyi +45 -0
  362. tigeropen/push/pb/__init__.py +7 -0
  363. tigeropen/push/pb/readme.md +5 -0
  364. tigeropen/push/pb/trade_tick.py +28 -0
  365. tigeropen/push/pb/util.py +251 -0
  366. tigeropen/push/protobuf_push_client.py +556 -0
  367. tigeropen/push/push_client.py +399 -0
  368. tigeropen/push/stomp_push_client.py +609 -0
  369. tigeropen/push/thread_pool.py +59 -0
  370. tigeropen/quote/__init__.py +6 -0
  371. tigeropen/quote/domain/__init__.py +6 -0
  372. tigeropen/quote/domain/bar.py +22 -0
  373. tigeropen/quote/domain/capital_distribution.py +19 -0
  374. tigeropen/quote/domain/filter.py +243 -0
  375. tigeropen/quote/domain/market_status.py +20 -0
  376. tigeropen/quote/domain/option_analysis.py +51 -0
  377. tigeropen/quote/domain/quote_brief.py +60 -0
  378. tigeropen/quote/domain/stock_broker.py +33 -0
  379. tigeropen/quote/domain/tick.py +18 -0
  380. tigeropen/quote/domain/timeline.py +17 -0
  381. tigeropen/quote/quote_client.py +3266 -0
  382. tigeropen/quote/request/__init__.py +8 -0
  383. tigeropen/quote/request/model.py +1614 -0
  384. tigeropen/quote/response/__init__.py +6 -0
  385. tigeropen/quote/response/broker_hold_response.py +23 -0
  386. tigeropen/quote/response/capital_distribution_response.py +24 -0
  387. tigeropen/quote/response/capital_flow_response.py +27 -0
  388. tigeropen/quote/response/fund_contracts_response.py +28 -0
  389. tigeropen/quote/response/future_briefs_response.py +36 -0
  390. tigeropen/quote/response/future_contract_response.py +44 -0
  391. tigeropen/quote/response/future_depth_response.py +31 -0
  392. tigeropen/quote/response/future_exchange_response.py +37 -0
  393. tigeropen/quote/response/future_history_main_contract_response.py +28 -0
  394. tigeropen/quote/response/future_quote_bar_response.py +42 -0
  395. tigeropen/quote/response/future_quote_ticks_response.py +25 -0
  396. tigeropen/quote/response/future_trading_times_response.py +42 -0
  397. tigeropen/quote/response/kline_quota_response.py +21 -0
  398. tigeropen/quote/response/market_scanner_response.py +48 -0
  399. tigeropen/quote/response/market_status_response.py +51 -0
  400. tigeropen/quote/response/option_analysis_response.py +64 -0
  401. tigeropen/quote/response/option_briefs_response.py +69 -0
  402. tigeropen/quote/response/option_chains_response.py +42 -0
  403. tigeropen/quote/response/option_depth_response.py +37 -0
  404. tigeropen/quote/response/option_expirations_response.py +34 -0
  405. tigeropen/quote/response/option_quote_bar_response.py +60 -0
  406. tigeropen/quote/response/option_quote_ticks_response.py +54 -0
  407. tigeropen/quote/response/option_symbols_response.py +25 -0
  408. tigeropen/quote/response/option_timeline_response.py +57 -0
  409. tigeropen/quote/response/quote_bar_response.py +36 -0
  410. tigeropen/quote/response/quote_brief_response.py +53 -0
  411. tigeropen/quote/response/quote_dataframe_response.py +35 -0
  412. tigeropen/quote/response/quote_delay_briefs_response.py +28 -0
  413. tigeropen/quote/response/quote_depth_response.py +31 -0
  414. tigeropen/quote/response/quote_grab_permission_response.py +21 -0
  415. tigeropen/quote/response/quote_hour_trading_timeline_response.py +66 -0
  416. tigeropen/quote/response/quote_overnight_response.py +19 -0
  417. tigeropen/quote/response/quote_ticks_response.py +66 -0
  418. tigeropen/quote/response/quote_timeline_history_response.py +65 -0
  419. tigeropen/quote/response/quote_timeline_response.py +81 -0
  420. tigeropen/quote/response/stock_briefs_response.py +36 -0
  421. tigeropen/quote/response/stock_broker_response.py +46 -0
  422. tigeropen/quote/response/stock_details_response.py +135 -0
  423. tigeropen/quote/response/stock_short_interest_response.py +43 -0
  424. tigeropen/quote/response/stock_trade_meta_response.py +39 -0
  425. tigeropen/quote/response/symbol_names_response.py +24 -0
  426. tigeropen/quote/response/symbols_response.py +23 -0
  427. tigeropen/quote/response/trade_rank_response.py +28 -0
  428. tigeropen/quote/response/trading_calendar_response.py +21 -0
  429. tigeropen/quote/response/warrant_briefs_response.py +24 -0
  430. tigeropen/quote/response/warrant_filter_response.py +27 -0
  431. tigeropen/tiger_open_client.py +278 -0
  432. tigeropen/tiger_open_config.py +574 -0
  433. tigeropen/trade/__init__.py +6 -0
  434. tigeropen/trade/domain/__init__.py +6 -0
  435. tigeropen/trade/domain/account.py +269 -0
  436. tigeropen/trade/domain/contract.py +164 -0
  437. tigeropen/trade/domain/option_exercise.py +94 -0
  438. tigeropen/trade/domain/order.py +314 -0
  439. tigeropen/trade/domain/position.py +78 -0
  440. tigeropen/trade/domain/prime_account.py +149 -0
  441. tigeropen/trade/domain/profile.py +20 -0
  442. tigeropen/trade/domain/transfer.py +157 -0
  443. tigeropen/trade/request/__init__.py +6 -0
  444. tigeropen/trade/request/model.py +2162 -0
  445. tigeropen/trade/response/__init__.py +14 -0
  446. tigeropen/trade/response/account_profile_response.py +29 -0
  447. tigeropen/trade/response/aggregate_assets_response.py +18 -0
  448. tigeropen/trade/response/analytics_asset_response.py +29 -0
  449. tigeropen/trade/response/assets_response.py +93 -0
  450. tigeropen/trade/response/contracts_response.py +42 -0
  451. tigeropen/trade/response/forex_order_response.py +20 -0
  452. tigeropen/trade/response/fund_details_response.py +29 -0
  453. tigeropen/trade/response/funding_history_response.py +30 -0
  454. tigeropen/trade/response/option_exercise_response.py +98 -0
  455. tigeropen/trade/response/order_id_response.py +43 -0
  456. tigeropen/trade/response/order_preview_response.py +17 -0
  457. tigeropen/trade/response/orders_response.py +163 -0
  458. tigeropen/trade/response/positions_response.py +79 -0
  459. tigeropen/trade/response/prime_assets_response.py +36 -0
  460. tigeropen/trade/response/segment_fund_response.py +69 -0
  461. tigeropen/trade/response/transactions_response.py +44 -0
  462. tigeropen/trade/response/transfer_response.py +104 -0
  463. tigeropen/trade/trade_client.py +1761 -0
  464. tigeropen-3.5.9.dist-info/METADATA +820 -0
  465. tigeropen-3.5.9.dist-info/RECORD +468 -0
  466. tigeropen-3.5.9.dist-info/WHEEL +5 -0
  467. tigeropen-3.5.9.dist-info/entry_points.txt +2 -0
  468. tigeropen-3.5.9.dist-info/top_level.txt +3 -0
Binary file
@@ -0,0 +1,7 @@
1
+ # -*- coding: utf-8 -*-
2
+ """
3
+ Created on 2018/9/16
4
+
5
+ @author: gaoan
6
+ """
7
+ __VERSION__ = '3.5.9'
@@ -0,0 +1,7 @@
1
+ # -*- coding: utf-8 -*-
2
+ """
3
+ TigerOpen CLI package.
4
+ """
5
+ from tigeropen.cli.main import main
6
+
7
+ __all__ = ['main']
@@ -0,0 +1,84 @@
1
+ # -*- coding: utf-8 -*-
2
+ """
3
+ Account commands: info, assets, analytics.
4
+ """
5
+ import click
6
+
7
+ from tigeropen.cli.client_factory import get_trade_client
8
+ from tigeropen.cli.formatting import render, to_records, is_empty
9
+
10
+
11
+ @click.group('account')
12
+ def account():
13
+ """Account information and assets."""
14
+ pass
15
+
16
+
17
+ @account.command('info')
18
+ @click.pass_context
19
+ def account_info(ctx):
20
+ """Show account information."""
21
+ client = get_trade_client(ctx.obj)
22
+ accounts = client.get_managed_accounts()
23
+ if not is_empty(accounts):
24
+ data = to_records(accounts)
25
+ render(data, ctx.obj['format'])
26
+ else:
27
+ click.echo('No account info available.')
28
+
29
+
30
+ def _segment_to_dict(segment):
31
+ """Serialize a Segment object to a plain dict."""
32
+ d = {k: v for k, v in segment.__dict__.items() if not k.startswith('_')}
33
+ d['currency_assets'] = {
34
+ currency: {k: v for k, v in ca.__dict__.items() if not k.startswith('_')}
35
+ for currency, ca in segment.currency_assets.items()
36
+ }
37
+ return d
38
+
39
+
40
+ def _portfolio_account_to_dict(account):
41
+ """Serialize a PortfolioAccount object to a plain dict."""
42
+ return {
43
+ 'account': account.account,
44
+ 'update_timestamp': account.update_timestamp,
45
+ 'segments': {
46
+ key: _segment_to_dict(seg)
47
+ for key, seg in account._segments.items()
48
+ },
49
+ }
50
+
51
+
52
+ @account.command('assets')
53
+ @click.option('--currency', default=None, help='Currency filter (USD, HKD, etc.).')
54
+ @click.pass_context
55
+ def account_assets(ctx, currency):
56
+ """Show account asset summary."""
57
+ client = get_trade_client(ctx.obj)
58
+ kwargs = {}
59
+ if currency:
60
+ kwargs['base_currency'] = currency
61
+ result = client.get_prime_assets(**kwargs)
62
+ if not is_empty(result):
63
+ render(_portfolio_account_to_dict(result), ctx.obj['format'])
64
+ else:
65
+ click.echo('No asset data available.')
66
+
67
+
68
+ @account.command('analytics')
69
+ @click.option('--start-date', default=None, help='Start date (YYYY-MM-DD).')
70
+ @click.option('--end-date', default=None, help='End date (YYYY-MM-DD).')
71
+ @click.pass_context
72
+ def account_analytics(ctx, start_date, end_date):
73
+ """Show asset analytics."""
74
+ client = get_trade_client(ctx.obj)
75
+ kwargs = {}
76
+ if start_date:
77
+ kwargs['start_date'] = start_date
78
+ if end_date:
79
+ kwargs['end_date'] = end_date
80
+ result = client.get_analytics_asset(**kwargs)
81
+ if not is_empty(result):
82
+ render(result, ctx.obj['format'])
83
+ else:
84
+ click.echo('No analytics data available.')
@@ -0,0 +1,79 @@
1
+ # -*- coding: utf-8 -*-
2
+ """
3
+ Client factory module for CLI.
4
+ Handles config resolution, private key loading, and lazy client creation.
5
+ """
6
+ import os
7
+ from pathlib import Path
8
+
9
+ from tigeropen import __VERSION__
10
+ from tigeropen.common.util.signature_utils import read_private_key
11
+ from tigeropen.tiger_open_config import TigerOpenClientConfig
12
+
13
+ DEFAULT_CONFIG_DIR = str(Path.home() / '.tigeropen')
14
+
15
+
16
+ def resolve_private_key(key_input):
17
+ """
18
+ Resolve private key from file path, PEM string, or raw key string.
19
+
20
+ :param key_input: file path, PEM string with headers, or raw key string
21
+ :return: stripped private key string (no PEM headers)
22
+ """
23
+ if not key_input:
24
+ return ''
25
+
26
+ # If it's an existing file path, read from file
27
+ if os.path.isfile(key_input):
28
+ return read_private_key(key_input)
29
+
30
+ # If it's a full PEM string with headers, strip them
31
+ if '-----BEGIN RSA PRIVATE KEY-----' in key_input:
32
+ return key_input.replace('-----BEGIN RSA PRIVATE KEY-----', '') \
33
+ .replace('-----END RSA PRIVATE KEY-----', '') \
34
+ .replace('\n', '').strip()
35
+
36
+ # Otherwise treat as raw key string
37
+ return key_input
38
+
39
+
40
+ def build_config(ctx_obj):
41
+ """
42
+ Build TigerOpenClientConfig from CLI context dict.
43
+
44
+ :param ctx_obj: dict with optional keys: config_path, tiger_id, account, private_key, language
45
+ :return: TigerOpenClientConfig
46
+ """
47
+ config_path = ctx_obj.get('config_path') or DEFAULT_CONFIG_DIR
48
+ config = TigerOpenClientConfig(enable_dynamic_domain=False,
49
+ props_path=config_path)
50
+ config._channel = f"tigercli"
51
+
52
+ if ctx_obj.get('tiger_id'):
53
+ config.tiger_id = ctx_obj['tiger_id']
54
+ if ctx_obj.get('account'):
55
+ config.account = ctx_obj['account']
56
+ if ctx_obj.get('private_key'):
57
+ config.private_key = resolve_private_key(ctx_obj['private_key'])
58
+ if ctx_obj.get('language'):
59
+ config.language = ctx_obj['language']
60
+
61
+ return config
62
+
63
+
64
+ def get_quote_client(ctx_obj):
65
+ """Lazily create and cache a QuoteClient."""
66
+ if '_quote_client' not in ctx_obj:
67
+ from tigeropen.quote.quote_client import QuoteClient
68
+ config = build_config(ctx_obj)
69
+ ctx_obj['_quote_client'] = QuoteClient(config, is_grab_permission=False)
70
+ return ctx_obj['_quote_client']
71
+
72
+
73
+ def get_trade_client(ctx_obj):
74
+ """Lazily create and cache a TradeClient."""
75
+ if '_trade_client' not in ctx_obj:
76
+ from tigeropen.trade.trade_client import TradeClient
77
+ config = build_config(ctx_obj)
78
+ ctx_obj['_trade_client'] = TradeClient(config)
79
+ return ctx_obj['_trade_client']
@@ -0,0 +1,129 @@
1
+ # -*- coding: utf-8 -*-
2
+ """
3
+ Config commands: init, show, set, path.
4
+ """
5
+ import os
6
+
7
+ import click
8
+ from jproperties import Properties
9
+
10
+ from tigeropen.tiger_open_config import DEFAULT_PROPS_FILE
11
+ from tigeropen.cli.client_factory import resolve_private_key, DEFAULT_CONFIG_DIR
12
+
13
+
14
+ @click.group('config')
15
+ def config():
16
+ """Manage tigeropen configuration."""
17
+ pass
18
+
19
+
20
+ @config.command('init')
21
+ @click.pass_context
22
+ def config_init(ctx):
23
+ """Interactive configuration setup."""
24
+ tiger_id = click.prompt('Tiger ID')
25
+ account = click.prompt('Account')
26
+
27
+ # Private key: support multi-line paste (PEM or raw base64).
28
+ # Read lines until an empty line signals end of input.
29
+ click.echo('Private Key (file path or key content, blank line to finish):')
30
+ lines = []
31
+ stdin = click.get_text_stream('stdin')
32
+ while True:
33
+ line = stdin.readline()
34
+ if not line: # EOF
35
+ break
36
+ line = line.rstrip('\n').rstrip('\r')
37
+ if not line and lines:
38
+ break
39
+ if line:
40
+ lines.append(line)
41
+ private_key = ''.join(lines)
42
+
43
+ if not private_key:
44
+ raise click.ClickException('Private key cannot be empty.')
45
+
46
+ secret_key = click.prompt('Secret Key (institutional only, press Enter to skip)',
47
+ default='', show_default=False)
48
+ config_dir = click.prompt('Config directory', default=DEFAULT_CONFIG_DIR)
49
+
50
+ os.makedirs(config_dir, exist_ok=True)
51
+ props_file = os.path.join(config_dir, DEFAULT_PROPS_FILE)
52
+
53
+ p = Properties()
54
+ p['tiger_id'] = tiger_id
55
+ p['account'] = account
56
+ p['private_key_pk8'] = resolve_private_key(private_key)
57
+
58
+ if secret_key:
59
+ p['secret_key'] = secret_key
60
+
61
+ with open(props_file, 'wb') as f:
62
+ p.store(f, encoding='utf-8')
63
+
64
+ click.echo(f'Config written to {props_file}')
65
+
66
+
67
+ @config.command('show')
68
+ @click.pass_context
69
+ def config_show(ctx):
70
+ """Display current configuration (private key masked)."""
71
+ config_path = ctx.obj.get('config_path') if ctx.obj else None
72
+ config_path = config_path or DEFAULT_CONFIG_DIR
73
+ if os.path.isdir(config_path):
74
+ props_file = os.path.join(config_path, DEFAULT_PROPS_FILE)
75
+ else:
76
+ props_file = config_path
77
+
78
+ if not os.path.exists(props_file):
79
+ click.echo(f'Config file not found: {props_file}')
80
+ return
81
+
82
+ p = Properties()
83
+ with open(props_file, 'rb') as f:
84
+ p.load(f, 'utf-8')
85
+
86
+ for key in p:
87
+ value = p[key].data
88
+ if 'private_key' in key and value:
89
+ # Mask: show first 4 and last 4 chars
90
+ if len(value) > 8:
91
+ value = value[:4] + '****' + value[-4:]
92
+ else:
93
+ value = '****'
94
+ click.echo(f'{key}={value}')
95
+
96
+
97
+ @config.command('set')
98
+ @click.argument('key')
99
+ @click.argument('value')
100
+ @click.pass_context
101
+ def config_set(ctx, key, value):
102
+ """Set a configuration value."""
103
+ config_path = ctx.obj.get('config_path') if ctx.obj else None
104
+ config_path = config_path or DEFAULT_CONFIG_DIR
105
+ if os.path.isdir(config_path):
106
+ props_file = os.path.join(config_path, DEFAULT_PROPS_FILE)
107
+ else:
108
+ props_file = config_path
109
+
110
+ p = Properties()
111
+ if os.path.exists(props_file):
112
+ with open(props_file, 'rb') as f:
113
+ p.load(f, 'utf-8')
114
+
115
+ p[key] = value
116
+
117
+ os.makedirs(os.path.dirname(props_file) if os.path.dirname(props_file) else '.', exist_ok=True)
118
+ with open(props_file, 'wb') as f:
119
+ p.store(f, encoding='utf-8')
120
+
121
+ click.echo(f'Set {key}={value}')
122
+
123
+
124
+ @config.command('path')
125
+ @click.pass_context
126
+ def config_path(ctx):
127
+ """Print the config directory path."""
128
+ config_dir = ctx.obj.get('config_path') if ctx.obj else None
129
+ click.echo(config_dir or DEFAULT_CONFIG_DIR)
@@ -0,0 +1,117 @@
1
+ # -*- coding: utf-8 -*-
2
+ """
3
+ Output formatting module for CLI.
4
+ Supports table, json, csv formats.
5
+ """
6
+ import csv
7
+ import io
8
+ import json
9
+ import sys
10
+
11
+ import pandas as pd
12
+
13
+
14
+ def is_empty(data):
15
+ """Check if data is empty (None, empty DataFrame, empty list, etc.)."""
16
+ if data is None:
17
+ return True
18
+ if isinstance(data, pd.DataFrame):
19
+ return data.empty
20
+ if isinstance(data, (list, dict)):
21
+ return len(data) == 0
22
+ return False
23
+
24
+
25
+ def to_records(items):
26
+ """Convert a list of domain objects to a list of dicts for rendering.
27
+ If items is already a DataFrame, return it as-is.
28
+ Handles objects with __dict__, __slots__ + to_dict(), or plain dicts."""
29
+ if isinstance(items, pd.DataFrame):
30
+ return items
31
+ records = []
32
+ for item in items:
33
+ if hasattr(item, 'to_dict'):
34
+ d = item.to_dict()
35
+ elif hasattr(item, '__dict__'):
36
+ d = item.__dict__
37
+ else:
38
+ records.append(item)
39
+ continue
40
+ # Flatten nested objects to str for display
41
+ flat = {}
42
+ for k, v in d.items():
43
+ if v is not None and hasattr(v, '__dict__') and not isinstance(v, (str, int, float, bool)):
44
+ flat[k] = str(v)
45
+ elif isinstance(v, list) and v and hasattr(v[0], '__dict__'):
46
+ flat[k] = str(v)
47
+ else:
48
+ flat[k] = v
49
+ records.append(flat)
50
+ return records
51
+
52
+
53
+ def render(data, fmt='table', file=None):
54
+ """
55
+ Render data in the specified format.
56
+
57
+ :param data: DataFrame, dict, list of dicts, string, or None
58
+ :param fmt: 'table', 'json', or 'csv'
59
+ :param file: output file object, defaults to sys.stdout
60
+ """
61
+ if file is None:
62
+ file = sys.stdout
63
+
64
+ if data is None:
65
+ return
66
+
67
+ if isinstance(data, str):
68
+ file.write(data + '\n')
69
+ return
70
+
71
+ if fmt == 'json':
72
+ _render_json(data, file)
73
+ elif fmt == 'csv':
74
+ _render_csv(data, file)
75
+ else:
76
+ _render_table(data, file)
77
+
78
+
79
+ def _render_table(data, file):
80
+ if isinstance(data, pd.DataFrame):
81
+ if data.empty:
82
+ return
83
+ file.write(data.to_string(index=False) + '\n')
84
+ elif isinstance(data, list) and data and isinstance(data[0], dict):
85
+ df = pd.DataFrame(data)
86
+ file.write(df.to_string(index=False) + '\n')
87
+ elif isinstance(data, dict):
88
+ for k, v in data.items():
89
+ file.write(f'{k}: {v}\n')
90
+ else:
91
+ file.write(str(data) + '\n')
92
+
93
+
94
+ def _render_json(data, file):
95
+ if isinstance(data, pd.DataFrame):
96
+ records = data.to_dict(orient='records')
97
+ file.write(json.dumps(records, ensure_ascii=False, indent=2) + '\n')
98
+ elif isinstance(data, (dict, list)):
99
+ file.write(json.dumps(data, ensure_ascii=False, indent=2, default=str) + '\n')
100
+ else:
101
+ file.write(json.dumps(str(data), ensure_ascii=False) + '\n')
102
+
103
+
104
+ def _render_csv(data, file):
105
+ if isinstance(data, pd.DataFrame):
106
+ if data.empty:
107
+ return
108
+ file.write(data.to_csv(index=False))
109
+ elif isinstance(data, list) and data and isinstance(data[0], dict):
110
+ writer = csv.DictWriter(file, fieldnames=data[0].keys())
111
+ writer.writeheader()
112
+ writer.writerows(data)
113
+ elif isinstance(data, dict):
114
+ writer = csv.writer(file)
115
+ writer.writerow(['key', 'value'])
116
+ for k, v in data.items():
117
+ writer.writerow([k, v])
@@ -0,0 +1,197 @@
1
+ # -*- coding: utf-8 -*-
2
+ """
3
+ Main CLI entry point for tigeropen.
4
+ """
5
+ import sys
6
+ import traceback
7
+
8
+ import click
9
+
10
+ from tigeropen import __VERSION__
11
+ from tigeropen.common.exceptions import ApiException
12
+ from tigeropen.cli.config_cmd import config
13
+ from tigeropen.cli.quote_cmd import quote
14
+ from tigeropen.cli.trade_cmd import trade
15
+ from tigeropen.cli.account_cmd import account
16
+
17
+ CONTEXT_SETTINGS = dict(help_option_names=['-h', '--help'])
18
+
19
+ GETTING_STARTED = """\
20
+ TigerOpen CLI v{version} — Tiger Brokers Open API
21
+
22
+ Getting started:
23
+
24
+ 1. Run interactive setup:
25
+ $ tigeropen config init
26
+
27
+ 2. Or set environment variables:
28
+ $ export TIGEROPEN_TIGER_ID="your_tiger_id"
29
+ $ export TIGEROPEN_PRIVATE_KEY="your_private_key"
30
+ $ export TIGEROPEN_ACCOUNT="your_account"
31
+
32
+ 3. Query market data:
33
+ $ tigeropen quote briefs AAPL TSLA
34
+ $ tigeropen quote bars AAPL --period day --limit 10
35
+
36
+ 4. Manage orders:
37
+ $ tigeropen trade order list
38
+ $ tigeropen trade position list
39
+
40
+ 5. View account:
41
+ $ tigeropen account assets
42
+
43
+ Run 'tigeropen -h' to see all commands and options.
44
+ Run 'tigeropen <command> -h' for help on a specific command.
45
+ """
46
+
47
+
48
+ class TigerCLI(click.Group):
49
+ """Custom click Group that catches API/generic exceptions and shows
50
+ a getting-started guide when invoked with no arguments."""
51
+
52
+ def invoke(self, ctx):
53
+ try:
54
+ return super().invoke(ctx)
55
+ except click.exceptions.Exit:
56
+ raise
57
+ except click.exceptions.Abort:
58
+ click.echo('Aborted.', err=True)
59
+ sys.exit(1)
60
+ except ApiException as e:
61
+ click.echo(f'API Error [{e.code}]: {e.msg}')
62
+ if ctx.obj and ctx.obj.get('verbose'):
63
+ traceback.print_exc()
64
+ sys.exit(1)
65
+ except Exception as e:
66
+ click.echo(f'Error: {e}')
67
+ if ctx.obj and ctx.obj.get('verbose'):
68
+ traceback.print_exc()
69
+ sys.exit(1)
70
+
71
+ # Global options that can appear anywhere in the command line
72
+ _GLOBAL_OPTIONS = {
73
+ '-f': 1, '--format': 1,
74
+ '-c': 1, '--config-path': 1,
75
+ '-l': 1, '--language': 1,
76
+ '-v': 0, '--verbose': 0,
77
+ }
78
+
79
+ def parse_args(self, ctx, args):
80
+ if not args:
81
+ click.echo(GETTING_STARTED.format(version=__VERSION__))
82
+ ctx.exit(0)
83
+ # Move global options to the front so Click's group parser can see them.
84
+ # This allows e.g. `tigeropen quote briefs AAPL -f json` to work.
85
+ front = []
86
+ rest = []
87
+ i = 0
88
+ args = list(args)
89
+ while i < len(args):
90
+ arg = args[i]
91
+ if arg in self._GLOBAL_OPTIONS:
92
+ n_values = self._GLOBAL_OPTIONS[arg]
93
+ front.append(arg)
94
+ for j in range(n_values):
95
+ if i + 1 + j < len(args):
96
+ front.append(args[i + 1 + j])
97
+ i += 1 + n_values
98
+ else:
99
+ rest.append(arg)
100
+ i += 1
101
+ return super().parse_args(ctx, front + rest)
102
+
103
+
104
+ @click.group(cls=TigerCLI, context_settings=CONTEXT_SETTINGS)
105
+ @click.option('--config-path', '-c', type=click.Path(), envvar='TIGEROPEN_PROPS_PATH',
106
+ help='Path to config directory or properties file.')
107
+ @click.option('--format', '-f', 'output_format',
108
+ type=click.Choice(['table', 'json', 'csv'], case_sensitive=False),
109
+ default='json', help='Output format.')
110
+ @click.option('--language', '-l',
111
+ type=click.Choice(['en_US', 'zh_CN', 'zh_TW'], case_sensitive=False),
112
+ default='en_US', help='Language.')
113
+ @click.option('--verbose', '-v', is_flag=True, help='Enable debug logging.')
114
+ @click.pass_context
115
+ def cli(ctx, config_path, output_format, language, verbose):
116
+ """TigerOpen CLI - Tiger Brokers Open API command line tool."""
117
+ ctx.ensure_object(dict)
118
+ ctx.obj['config_path'] = config_path
119
+ ctx.obj['format'] = output_format
120
+ ctx.obj['language'] = language
121
+ ctx.obj['verbose'] = verbose
122
+
123
+
124
+ @cli.command('version')
125
+ def version():
126
+ """Print the SDK version."""
127
+ click.echo(__VERSION__)
128
+
129
+
130
+ @cli.command('uninstall')
131
+ @click.option('--remove-config', is_flag=True, help='Also remove ~/.tigeropen/ configuration directory.')
132
+ @click.option('-y', '--yes', is_flag=True, help='Skip confirmation prompts.')
133
+ def uninstall(remove_config, yes):
134
+ """Uninstall tigeropen and optionally remove configuration."""
135
+ import subprocess
136
+ import shutil
137
+ from pathlib import Path
138
+
139
+ if not yes:
140
+ msg = 'Uninstall tigeropen?'
141
+ if remove_config:
142
+ msg += ' (including ~/.tigeropen/ config directory)'
143
+ if not click.confirm(msg):
144
+ raise SystemExit(0)
145
+
146
+ # Remove config directory first (before pip uninstall removes the CLI itself)
147
+ if remove_config:
148
+ config_dir = Path.home() / '.tigeropen'
149
+ if config_dir.exists():
150
+ shutil.rmtree(config_dir)
151
+ click.echo(f'Removed {config_dir}')
152
+ else:
153
+ click.echo(f'{config_dir} not found, skipping.')
154
+
155
+ # Run pip uninstall with the same Python interpreter
156
+ click.echo('Uninstalling tigeropen...')
157
+ result = subprocess.run(
158
+ [sys.executable, '-m', 'pip', 'uninstall', 'tigeropen', '-y'],
159
+ capture_output=True, text=True,
160
+ )
161
+ if result.returncode == 0:
162
+ click.echo('tigeropen has been uninstalled.')
163
+ else:
164
+ click.echo(f'pip uninstall failed:\n{result.stderr.strip()}', err=True)
165
+ sys.exit(1)
166
+
167
+
168
+ cli.add_command(config)
169
+ cli.add_command(quote)
170
+ cli.add_command(trade)
171
+ cli.add_command(account)
172
+
173
+
174
+ def _load_push_command():
175
+ """Lazy-load push command to avoid importing protobuf at startup."""
176
+ try:
177
+ from tigeropen.cli.push_cmd import push
178
+ cli.add_command(push)
179
+ except ImportError:
180
+ @cli.command('push')
181
+ @click.argument('args', nargs=-1)
182
+ def push_unavailable(args):
183
+ """Real-time data streaming (requires protobuf>=5.28)."""
184
+ click.echo('Error: push command requires protobuf>=5.28.\n'
185
+ 'Please upgrade: pip install --upgrade protobuf')
186
+ sys.exit(1)
187
+
188
+
189
+ _load_push_command()
190
+
191
+
192
+ def main():
193
+ cli()
194
+
195
+
196
+ if __name__ == '__main__':
197
+ main()