pyqqq 0.12.178__tar.gz → 0.12.179__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.

Potentially problematic release.


This version of pyqqq might be problematic. Click here for more details.

Files changed (63) hide show
  1. {pyqqq-0.12.178 → pyqqq-0.12.179}/PKG-INFO +1 -1
  2. {pyqqq-0.12.178 → pyqqq-0.12.179}/pyproject.toml +1 -1
  3. {pyqqq-0.12.178 → pyqqq-0.12.179}/pyqqq/backtest/broker.py +32 -1
  4. {pyqqq-0.12.178 → pyqqq-0.12.179}/pyqqq/backtest/environment.py +10 -2
  5. {pyqqq-0.12.178 → pyqqq-0.12.179}/pyqqq/utils/position_classifier.py +1 -1
  6. {pyqqq-0.12.178 → pyqqq-0.12.179}/README.md +0 -0
  7. {pyqqq-0.12.178 → pyqqq-0.12.179}/pyqqq/__init__.py +0 -0
  8. {pyqqq-0.12.178 → pyqqq-0.12.179}/pyqqq/ai/__init__.py +0 -0
  9. {pyqqq-0.12.178 → pyqqq-0.12.179}/pyqqq/ai/daily.py +0 -0
  10. {pyqqq-0.12.178 → pyqqq-0.12.179}/pyqqq/ai/domestic.py +0 -0
  11. {pyqqq-0.12.178 → pyqqq-0.12.179}/pyqqq/ai/market_schedule.py +0 -0
  12. {pyqqq-0.12.178 → pyqqq-0.12.179}/pyqqq/ai/minute.py +0 -0
  13. {pyqqq-0.12.178 → pyqqq-0.12.179}/pyqqq/backtest/__init__.py +0 -0
  14. {pyqqq-0.12.178 → pyqqq-0.12.179}/pyqqq/backtest/logger.py +0 -0
  15. {pyqqq-0.12.178 → pyqqq-0.12.179}/pyqqq/backtest/positionprovider.py +0 -0
  16. {pyqqq-0.12.178 → pyqqq-0.12.179}/pyqqq/backtest/strategy.py +0 -0
  17. {pyqqq-0.12.178 → pyqqq-0.12.179}/pyqqq/backtest/utils.py +0 -0
  18. {pyqqq-0.12.178 → pyqqq-0.12.179}/pyqqq/backtest/wallclock.py +0 -0
  19. {pyqqq-0.12.178 → pyqqq-0.12.179}/pyqqq/brokerage/__init__.py +0 -0
  20. {pyqqq-0.12.178 → pyqqq-0.12.179}/pyqqq/brokerage/ebest/__init__.py +0 -0
  21. {pyqqq-0.12.178 → pyqqq-0.12.179}/pyqqq/brokerage/ebest/domestic_stock.py +0 -0
  22. {pyqqq-0.12.178 → pyqqq-0.12.179}/pyqqq/brokerage/ebest/oauth.py +0 -0
  23. {pyqqq-0.12.178 → pyqqq-0.12.179}/pyqqq/brokerage/ebest/simple.py +0 -0
  24. {pyqqq-0.12.178 → pyqqq-0.12.179}/pyqqq/brokerage/ebest/tr_client.py +0 -0
  25. {pyqqq-0.12.178 → pyqqq-0.12.179}/pyqqq/brokerage/helper.py +0 -0
  26. {pyqqq-0.12.178 → pyqqq-0.12.179}/pyqqq/brokerage/kis/__init__.py +0 -0
  27. {pyqqq-0.12.178 → pyqqq-0.12.179}/pyqqq/brokerage/kis/domestic_stock.py +0 -0
  28. {pyqqq-0.12.178 → pyqqq-0.12.179}/pyqqq/brokerage/kis/oauth.py +0 -0
  29. {pyqqq-0.12.178 → pyqqq-0.12.179}/pyqqq/brokerage/kis/overseas_stock.py +0 -0
  30. {pyqqq-0.12.178 → pyqqq-0.12.179}/pyqqq/brokerage/kis/simple.py +0 -0
  31. {pyqqq-0.12.178 → pyqqq-0.12.179}/pyqqq/brokerage/kis/simple_overseas.py +0 -0
  32. {pyqqq-0.12.178 → pyqqq-0.12.179}/pyqqq/brokerage/kis/tr_client.py +0 -0
  33. {pyqqq-0.12.178 → pyqqq-0.12.179}/pyqqq/brokerage/multiprocess_tracker.py +0 -0
  34. {pyqqq-0.12.178 → pyqqq-0.12.179}/pyqqq/brokerage/tracker.py +0 -0
  35. {pyqqq-0.12.178 → pyqqq-0.12.179}/pyqqq/config.py +0 -0
  36. {pyqqq-0.12.178 → pyqqq-0.12.179}/pyqqq/data/__init__.py +0 -0
  37. {pyqqq-0.12.178 → pyqqq-0.12.179}/pyqqq/data/daily.py +0 -0
  38. {pyqqq-0.12.178 → pyqqq-0.12.179}/pyqqq/data/domestic.py +0 -0
  39. {pyqqq-0.12.178 → pyqqq-0.12.179}/pyqqq/data/index.py +0 -0
  40. {pyqqq-0.12.178 → pyqqq-0.12.179}/pyqqq/data/minutes.py +0 -0
  41. {pyqqq-0.12.178 → pyqqq-0.12.179}/pyqqq/data/overseas.py +0 -0
  42. {pyqqq-0.12.178 → pyqqq-0.12.179}/pyqqq/data/realtime.py +0 -0
  43. {pyqqq-0.12.178 → pyqqq-0.12.179}/pyqqq/data/ticks.py +0 -0
  44. {pyqqq-0.12.178 → pyqqq-0.12.179}/pyqqq/data/us_stocks.py +0 -0
  45. {pyqqq-0.12.178 → pyqqq-0.12.179}/pyqqq/datatypes.py +0 -0
  46. {pyqqq-0.12.178 → pyqqq-0.12.179}/pyqqq/executors/__init__.py +0 -0
  47. {pyqqq-0.12.178 → pyqqq-0.12.179}/pyqqq/executors/hook.py +0 -0
  48. {pyqqq-0.12.178 → pyqqq-0.12.179}/pyqqq/utils/__init__.py +0 -0
  49. {pyqqq-0.12.178 → pyqqq-0.12.179}/pyqqq/utils/api_client.py +0 -0
  50. {pyqqq-0.12.178 → pyqqq-0.12.179}/pyqqq/utils/array.py +0 -0
  51. {pyqqq-0.12.178 → pyqqq-0.12.179}/pyqqq/utils/casting.py +0 -0
  52. {pyqqq-0.12.178 → pyqqq-0.12.179}/pyqqq/utils/compute.py +0 -0
  53. {pyqqq-0.12.178 → pyqqq-0.12.179}/pyqqq/utils/copycat.py +0 -0
  54. {pyqqq-0.12.178 → pyqqq-0.12.179}/pyqqq/utils/daily_tickers.py +0 -0
  55. {pyqqq-0.12.178 → pyqqq-0.12.179}/pyqqq/utils/display.py +0 -0
  56. {pyqqq-0.12.178 → pyqqq-0.12.179}/pyqqq/utils/kvstore.py +0 -0
  57. {pyqqq-0.12.178 → pyqqq-0.12.179}/pyqqq/utils/limiter.py +0 -0
  58. {pyqqq-0.12.178 → pyqqq-0.12.179}/pyqqq/utils/local_cache.py +0 -0
  59. {pyqqq-0.12.178 → pyqqq-0.12.179}/pyqqq/utils/logger.py +0 -0
  60. {pyqqq-0.12.178 → pyqqq-0.12.179}/pyqqq/utils/market_schedule.py +0 -0
  61. {pyqqq-0.12.178 → pyqqq-0.12.179}/pyqqq/utils/mock_api.py +0 -0
  62. {pyqqq-0.12.178 → pyqqq-0.12.179}/pyqqq/utils/retry.py +0 -0
  63. {pyqqq-0.12.178 → pyqqq-0.12.179}/pyqqq/utils/singleton.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: pyqqq
3
- Version: 0.12.178
3
+ Version: 0.12.179
4
4
  Summary: Package for quantitative strategy development on the PyQQQ platform
5
5
  License: MIT
6
6
  Author: PyQQQ team
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "pyqqq"
3
- version = "0.12.178"
3
+ version = "0.12.179"
4
4
  description = "Package for quantitative strategy development on the PyQQQ platform"
5
5
  authors = ["PyQQQ team <pyqqq.cs@gmail.com>"]
6
6
  readme = "README.md"
@@ -25,6 +25,7 @@ from pyqqq.data.us_stocks import get_ticker_info as get_us_ticker_info
25
25
  from pyqqq.datatypes import *
26
26
  from pyqqq.utils.casting import casting
27
27
  from pyqqq.utils.market_schedule import get_last_trading_day, get_market_schedule, get_trading_day_with_offset
28
+ from pyqqq.utils.position_classfier import PositionClassifier
28
29
 
29
30
  MarketType = Literal["kr_stock", "us_stock"]
30
31
 
@@ -249,6 +250,8 @@ class TradingBroker(BaseBroker):
249
250
  trading_api: Union[KISSimpleDomesticStock, KISSimpleOverseasStock],
250
251
  clock: WallClock,
251
252
  market_nxt_on: bool = False,
253
+ strategy_name: Optional[str] = None,
254
+ classifier_type: Optional[str] = None,
252
255
  ):
253
256
  """TradingBroker 클래스의 초기화 메서드입니다.
254
257
 
@@ -266,6 +269,14 @@ class TradingBroker(BaseBroker):
266
269
  self.data_api = data_api
267
270
  self.trading_api = trading_api
268
271
  self.market_nxt_on = market_nxt_on
272
+ self.position_classifier = None
273
+
274
+ if classifier_type and classifier_type in ["auto", "direct"]:
275
+ if strategy_name:
276
+ kv_store_collection = f"{strategy_name}_classifier"
277
+ else:
278
+ kv_store_collection = f"account_{self.trading_api.account_no}_classifier"
279
+ self.position_classifier = PositionClassifier(simple_data_api=self.trading_api, kv_store_collection=kv_store_collection, default_type=classifier_type)
269
280
 
270
281
  def get_account(self) -> dict:
271
282
  return self.trading_api.get_account()
@@ -350,7 +361,20 @@ class TradingBroker(BaseBroker):
350
361
 
351
362
  def create_order(self, asset_code: str, side: OrderSide, quantity: int, order_type: OrderType = OrderType.MARKET, price: int | Decimal = 0, exchange: OrderExchange = OrderExchange.KRX) -> str:
352
363
  self.logger.debug(f"create_order: {asset_code} {side} {quantity} {order_type} {price} {exchange}")
353
- return self.trading_api.create_order(asset_code, side, quantity, order_type, price, exchange=exchange)
364
+
365
+ if side is OrderSide.SELL and self.position_classifier:
366
+ # 포지션 분류기를 사용하여 전략에서 보유중인 수량으로 매도 가능 수량 재 계산
367
+ calc_quantity = self.position_classifier.get_sellable_quantity(asset_code, quantity)
368
+
369
+ if calc_quantity != quantity:
370
+ self.logger.warning(f"Requested sell quantity {quantity} for {asset_code} adjusted to {calc_quantity} based on position classifier.")
371
+ quantity = calc_quantity
372
+
373
+ order_no = self.trading_api.create_order(asset_code, side, quantity, order_type, price, exchange=exchange)
374
+ if order_no and self.position_classifier:
375
+ # 주문이 성공적으로 생성되면 포지션 분류기에 주문 정보를 업데이트
376
+ self.position_classifier.tagging_order_auto(order_no)
377
+ return order_no
354
378
 
355
379
  def update_order(self, org_order_no: str, order_type: OrderType, price: int | Decimal, quantity: int = 0, exchange: OrderExchange = OrderExchange.KRX):
356
380
  if isinstance(self.trading_api, KISSimpleOverseasStock):
@@ -387,6 +411,13 @@ class TradingBroker(BaseBroker):
387
411
  self.logger.debug(f"cancel_order: {order_no} {quantity}")
388
412
  return self.trading_api.cancel_order(order_no, quantity)
389
413
 
414
+ async def start_classifier(self):
415
+ """ 포지션 분류기를 시작합니다.
416
+ 이 메서드는 포지션 분류기를 사용한다면 반드시 호출해야 합니다.
417
+ """
418
+ if self.position_classifier:
419
+ await self.position_classifier.start()
420
+
390
421
 
391
422
  # 백테스팅 할때 사용되는 브로커
392
423
  class MockBroker(BaseBroker):
@@ -1,7 +1,7 @@
1
1
  import datetime as dtm
2
2
  import os
3
3
  from abc import ABC
4
- from typing import Literal
4
+ from typing import Literal, Optional
5
5
  from zoneinfo import ZoneInfo
6
6
 
7
7
  from pyqqq.backtest.broker import BaseBroker, MockBroker, TradingBroker
@@ -142,12 +142,18 @@ class KISDomesticEnvironment(TradingEnvironment):
142
142
  ```
143
143
  """
144
144
 
145
- def __init__(self, paper_trading: bool = False, market_nxt_on: bool = False):
145
+ def __init__(self, paper_trading: bool = False, market_nxt_on: bool = False, strategy_name: Optional[str] = None, classifier_type: Optional[str] = None):
146
146
  """KISDomesticEnvironment 클래스의 초기화 메서드입니다.
147
147
 
148
148
  Args:
149
149
  paper_trading (bool, optional): 모의투자 사용 여부. Defaults to False.
150
150
  True일 경우 모의투자 계좌 사용
151
+ market_nxt_on (bool, optional): NXT 시장 처리 여부. Defaults to False.
152
+ strategy_name (str, optional): 전략 이름. Defaults to None.
153
+ position classifier 데이터가 저장되는 kvstore collection 이름에 사용됨.
154
+ classifier_type (str, optional): "direct", "auto" 중 하나로 설정시 position classifier 사용하게 됨. Defaults to None.
155
+ 해당 값은 분류기가 기본 포지션을 어떤 방식으로 결정할지에 대한 설정.
156
+
151
157
 
152
158
  Raises:
153
159
  KeyError: 필요한 환경변수가 설정되지 않은 경우
@@ -160,6 +166,8 @@ class KISDomesticEnvironment(TradingEnvironment):
160
166
  trading_api=conn.broker_simple if not paper_trading else conn.paper_broker_simple,
161
167
  clock=self.clock,
162
168
  market_nxt_on=market_nxt_on,
169
+ strategy_name=strategy_name,
170
+ classifier_type=classifier_type,
163
171
  )
164
172
 
165
173
 
@@ -107,7 +107,7 @@ class PositionClassifier:
107
107
  self.logger.info(f"set_initial_position.\npositions: {cur_pos}\nauto_positions: {self.auto_positions}\ndirect_positions: {self.direct_positions}")
108
108
 
109
109
  def set_initial_order(self):
110
- cur_order = self.api.get_pending_orders()
110
+ cur_order = self.api.get_pending_orders(exchanges=[OrderExchange.KRX, OrderExchange.NXT, OrderExchange.SOR])
111
111
  kv_auto_orders = self.kv_store.get(self.DEF_AUTO_ORDER_KEY) or {}
112
112
  kv_direct_orders = self.kv_store.get(self.DEF_DIRECT_ORDER_KEY) or {}
113
113
  kv_auto_tag_orders = self.kv_store.get(self.DEF_TAG_AUTO_ORDER_KEY) or []
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes