orionapi 2.22.0__tar.gz → 2.24.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: orionapi
3
- Version: 2.22.0
3
+ Version: 2.24.0
4
4
  Summary: A python interface for the Orion Advisors platform web API
5
5
  Author: spencerogden-dsam
6
6
  Author-email: 67068943+spencerogden-dsam@users.noreply.github.com
@@ -1,4 +1,4 @@
1
- __version__ = "2.22.0"
1
+ __version__ = "2.24.0"
2
2
 
3
3
  import logging
4
4
  import re
@@ -2406,6 +2406,7 @@ class EclipseV1(EclipseBase):
2406
2406
  expire_date=None,
2407
2407
  expire_trans_tol=0,
2408
2408
  expire_trans_type=1,
2409
+ deplete_over_time=False,
2409
2410
  percent_calc_type=0,
2410
2411
  sync=True,
2411
2412
  ):
@@ -2423,6 +2424,9 @@ class EclipseV1(EclipseBase):
2423
2424
  expire_date: Expiration date (if expire_type='Date')
2424
2425
  expire_trans_tol: Transaction tolerance value (default 0)
2425
2426
  expire_trans_type: 1='Distribution / Merge Out', 3='Fee' (default 1)
2427
+ deplete_over_time: Maps to the UI "Deplete Over Time" checkbox
2428
+ (``isDepleteOverTime``). Only meaningful when
2429
+ expire_type='Transaction' (default False)
2426
2430
  percent_calc_type: 0='Use Default/Managed Value', 1='Use Total Value',
2427
2431
  2='Use Excluded Value' (default 0)
2428
2432
  sync: Wait for analytics to complete (default True)
@@ -2487,6 +2491,7 @@ class EclipseV1(EclipseBase):
2487
2491
  "expirationValue": expire_value,
2488
2492
  "toleranceValue": expire_trans_tol,
2489
2493
  "transactionTypeId": expire_trans_type,
2494
+ "isDepleteOverTime": bool(deplete_over_time),
2490
2495
  "description": description,
2491
2496
  "percentCalculationTypeId": percent_calc_type,
2492
2497
  },
@@ -2743,33 +2748,68 @@ class EclipseV1(EclipseBase):
2743
2748
  self.wait_for_analytics()
2744
2749
 
2745
2750
  def get_orders(self):
2746
- """Get all completed (non-pending) trade orders.
2751
+ """Deprecated alias of ``get_trades(is_pending=False)``.
2752
+
2753
+ Both hit the same ``/tradeorder/trades`` endpoint; :meth:`get_trades` is the
2754
+ superset and also exposes the portfolio, block, filter and account filters.
2755
+ Emits a ``DeprecationWarning`` and will be removed in a future major release.
2747
2756
 
2748
2757
  Returns:
2749
2758
  list: List of completed trade order dicts
2750
2759
  """
2751
- return self.api_request(f"{self.base_url}/tradeorder/trades?isPending=false").json()
2760
+ warnings.warn(
2761
+ "get_orders is deprecated; use get_trades(is_pending=False).",
2762
+ DeprecationWarning,
2763
+ stacklevel=2,
2764
+ )
2765
+ return self.get_trades(is_pending=False)
2752
2766
 
2753
2767
  def get_orders_pending(self):
2754
- """Get all pending trade orders.
2768
+ """Deprecated alias of ``get_trades(is_pending=True)``.
2769
+
2770
+ Both hit the same ``/tradeorder/trades`` endpoint; :meth:`get_trades` is the
2771
+ superset and also exposes the portfolio, block, filter and account filters.
2772
+ Emits a ``DeprecationWarning`` and will be removed in a future major release.
2755
2773
 
2756
2774
  Returns:
2757
2775
  list: List of pending trade order dicts
2758
2776
  """
2759
- return self.api_request(f"{self.base_url}/tradeorder/trades?isPending=true").json()
2777
+ warnings.warn(
2778
+ "get_orders_pending is deprecated; use get_trades(is_pending=True).",
2779
+ DeprecationWarning,
2780
+ stacklevel=2,
2781
+ )
2782
+ return self.get_trades(is_pending=True)
2760
2783
 
2761
- def get_trades(self, portfolio_id=None, top=None, is_pending=None):
2762
- """Get trade orders with optional portfolio / paging / pending filters.
2784
+ def get_trades(
2785
+ self,
2786
+ portfolio_id=None,
2787
+ top=None,
2788
+ is_pending=None,
2789
+ block_id=None,
2790
+ filter_id=None,
2791
+ account_ids=None,
2792
+ ):
2793
+ """Get trade orders with optional portfolio / block / filter / pending filters.
2763
2794
 
2764
- Hits the same ``/tradeorder/trades`` endpoint as :meth:`get_orders` /
2765
- :meth:`get_orders_pending`, but lets the caller filter by portfolio and cap
2766
- the result count.
2795
+ The canonical accessor for ``GET /tradeorder/trades``. Supersedes the
2796
+ deprecated :meth:`get_orders` / :meth:`get_orders_pending`, which only
2797
+ varied ``is_pending``.
2767
2798
 
2768
2799
  Args:
2769
2800
  portfolio_id: Optional portfolio ID filter (maps to ``portfolioId``)
2770
- top: Optional max number of results (maps to ``$top``)
2801
+ top: Deprecated and ignored. ``$top`` is not a documented param on this
2802
+ endpoint, and Eclipse silently drops unknown query params rather
2803
+ than erroring — live-verified 2026-07-28: with 10 trades in the
2804
+ tenant, ``$top=3`` still returned all 10. Slice the result instead.
2771
2805
  is_pending: Optional bool; when set, filter by pending status
2772
2806
  (maps to ``isPending``)
2807
+ block_id: Optional trade block ID filter (maps to ``blockId``)
2808
+ filter_id: Optional trade filter type ID (maps to ``filterId``); see
2809
+ the ``/tradeorder/trades/filterTypes`` endpoint for valid values
2810
+ account_ids: Optional account ID filter (maps to ``accountIds``);
2811
+ accepts a list/tuple of IDs, which is joined to a comma-separated
2812
+ string, or a pre-formatted string
2773
2813
 
2774
2814
  Returns:
2775
2815
  list: Trade order dicts
@@ -2778,12 +2818,189 @@ class EclipseV1(EclipseBase):
2778
2818
  if portfolio_id is not None:
2779
2819
  params["portfolioId"] = portfolio_id
2780
2820
  if top is not None:
2781
- params["$top"] = top
2821
+ warnings.warn(
2822
+ "get_trades(top=...) is ignored by Eclipse: $top is not a supported "
2823
+ "param on /tradeorder/trades and the server silently drops it. "
2824
+ "Slice the returned list instead. This parameter will be removed in "
2825
+ "a future major release.",
2826
+ DeprecationWarning,
2827
+ stacklevel=2,
2828
+ )
2782
2829
  if is_pending is not None:
2783
2830
  params["isPending"] = str(is_pending).lower()
2831
+ if block_id is not None:
2832
+ params["blockId"] = block_id
2833
+ if filter_id is not None:
2834
+ params["filterId"] = filter_id
2835
+ if account_ids is not None:
2836
+ if isinstance(account_ids, (list, tuple)):
2837
+ account_ids = ",".join(str(a) for a in account_ids)
2838
+ params["accountIds"] = account_ids
2784
2839
  res = self.api_request(f"{self.base_url}/tradeorder/trades", params=params)
2785
2840
  return res.json()
2786
2841
 
2842
+ def validate_trade(
2843
+ self,
2844
+ action_id,
2845
+ account_id=None,
2846
+ portfolio_id=None,
2847
+ security_id=None,
2848
+ dollar_amount=None,
2849
+ quantity=None,
2850
+ percentage=None,
2851
+ is_auto_allocate=None,
2852
+ ):
2853
+ """Validate a trade before creating it (``POST /tradeorder/trades/validate``).
2854
+
2855
+ Writes nothing. Use this as the pre-flight check for :meth:`create_trade`,
2856
+ which has no preview / view-only mode of its own.
2857
+
2858
+ Args:
2859
+ action_id: 1=Buy, 2=Sell, 3=Journal In, 4=Journal Out
2860
+ account_id: Optional account ID
2861
+ portfolio_id: Optional portfolio ID
2862
+ security_id: Optional security ID
2863
+ dollar_amount: Optional dollar amount to buy/sell
2864
+ quantity: Optional number of shares to buy/sell
2865
+ percentage: Optional percent of the position to buy/sell
2866
+ is_auto_allocate: Optional bool (maps to ``isAutoAllocate``)
2867
+
2868
+ Returns:
2869
+ dict: ``message``, ``tradeAmount``, ``cashValuePostTrade`` and a
2870
+ ``warningMessage`` list (e.g. warnings about overspending cash)
2871
+ """
2872
+ payload = {
2873
+ "actionId": action_id,
2874
+ "accountId": account_id,
2875
+ "portfolioId": portfolio_id,
2876
+ "securityId": security_id,
2877
+ "dollarAmount": dollar_amount,
2878
+ "quantity": quantity,
2879
+ "percentage": percentage,
2880
+ "isAutoAllocate": is_auto_allocate,
2881
+ }
2882
+ payload = {k: v for k, v in payload.items() if v is not None}
2883
+
2884
+ res = self.api_request(
2885
+ f"{self.base_url}/tradeorder/trades/validate", requests.post, json=payload
2886
+ )
2887
+ return res.json()
2888
+
2889
+ def create_trade(
2890
+ self,
2891
+ action_id,
2892
+ trade_tool_selection,
2893
+ trade_instance_type,
2894
+ trade_instance_sub_type,
2895
+ account_id=None,
2896
+ portfolio_id=None,
2897
+ security_id=None,
2898
+ dollar_amount=None,
2899
+ quantity=None,
2900
+ percentage=None,
2901
+ sync=True,
2902
+ ):
2903
+ """Generate trade orders (``POST /tradeorder/trades``).
2904
+
2905
+ The generic per-trade creator behind Eclipse's Quick Trade / journal flows,
2906
+ as opposed to the ``/tradetool/`` generators (:meth:`cash_needs_trade`,
2907
+ :meth:`rebalance_trade`, ...) which operate on whole portfolios.
2908
+
2909
+ .. warning::
2910
+ This endpoint has **no view-only mode** — it always writes. Call
2911
+ :meth:`validate_trade` first to preview the trade amount, the resulting
2912
+ cash balance and any warnings.
2913
+
2914
+ Trades are always created as pending orders: the wrapper hardcodes
2915
+ ``isSendImmediately: false`` and deliberately does not expose it, so a
2916
+ single call can never both create and execute a trade. Review and
2917
+ execute the resulting orders in Eclipse.
2918
+
2919
+ Args:
2920
+ action_id: 1=Buy, 2=Sell, 3=Journal In, 4=Journal Out. (The Eclipse
2921
+ docs list both journal directions as ``3``; ``4`` is accepted on
2922
+ the assumption that Journal Out is ``4``.)
2923
+ trade_tool_selection: 1=Portfolio, 2=Account, 3=Model,
2924
+ 4=Account Trade Group, 5=Sleeve Portfolio, 6=Excel Import,
2925
+ 7=Portfolio Trade Group, 8=Security Import, 9=Individual Sleeve,
2926
+ 10=Tactical Tool
2927
+ trade_instance_type: Trade instance type ID; see
2928
+ :data:`TRADE_INSTANCE_TYPES`
2929
+ trade_instance_sub_type: Trade instance sub-type ID; see
2930
+ :data:`TRADE_INSTANCE_SUBTYPES`
2931
+ account_id: Account ID (required unless ``portfolio_id`` is given)
2932
+ portfolio_id: Portfolio ID (required unless ``account_id`` is given)
2933
+ security_id: Security ID; required for buys and sells
2934
+ dollar_amount: Dollar amount to buy/sell
2935
+ quantity: Number of shares to buy/sell
2936
+ percentage: Percent of the position to buy/sell
2937
+ sync: Wait for analytics to complete (default True)
2938
+
2939
+ Returns:
2940
+ dict: Either ``{"message": ...}`` or ``{"issues": [...],
2941
+ "success": [...], "instanceId": ...}``
2942
+
2943
+ Raises:
2944
+ ValueError: If the enum values are unknown, option trading is
2945
+ requested (unsupported by Eclipse), neither an account nor a
2946
+ portfolio is given, or a buy/sell does not specify exactly one of
2947
+ ``dollar_amount`` / ``quantity`` / ``percentage``.
2948
+ """
2949
+ if action_id not in (1, 2, 3, 4):
2950
+ raise ValueError(
2951
+ "action_id must be 1 (Buy), 2 (Sell), 3 (Journal In) or 4 (Journal Out)"
2952
+ )
2953
+ if trade_tool_selection not in range(1, 11):
2954
+ raise ValueError("trade_tool_selection must be an integer between 1 and 10")
2955
+ if trade_instance_type not in TRADE_INSTANCE_TYPES:
2956
+ raise ValueError(
2957
+ f"trade_instance_type must be one of {sorted(TRADE_INSTANCE_TYPES)}, "
2958
+ f"got {trade_instance_type!r}"
2959
+ )
2960
+ if trade_instance_sub_type not in TRADE_INSTANCE_SUBTYPES:
2961
+ raise ValueError(
2962
+ f"trade_instance_sub_type must be one of {sorted(TRADE_INSTANCE_SUBTYPES)}, "
2963
+ f"got {trade_instance_sub_type!r}"
2964
+ )
2965
+ # Eclipse documents option trading as "not supported" on this endpoint.
2966
+ if trade_instance_type == 4 or trade_instance_sub_type == 9:
2967
+ raise ValueError("Option Trading is not supported by the /tradeorder/trades endpoint")
2968
+ if account_id is None and portfolio_id is None:
2969
+ raise ValueError("at least one of account_id or portfolio_id is required")
2970
+
2971
+ is_buy_or_sell = action_id in (1, 2)
2972
+ if is_buy_or_sell:
2973
+ if security_id is None:
2974
+ raise ValueError("security_id is required for buys and sells")
2975
+ amounts = [a for a in (dollar_amount, quantity, percentage) if a]
2976
+ if len(amounts) != 1:
2977
+ raise ValueError(
2978
+ "exactly one of dollar_amount, quantity or percentage must be set "
2979
+ "for buys and sells"
2980
+ )
2981
+
2982
+ # Buys/sells send 0 for the unused amount fields; journals send null.
2983
+ unset = 0 if is_buy_or_sell else None
2984
+ payload = {
2985
+ "accountId": account_id,
2986
+ "portfolioId": portfolio_id,
2987
+ "actionId": action_id,
2988
+ "securityId": security_id,
2989
+ "dollarAmount": dollar_amount if dollar_amount is not None else unset,
2990
+ "quantity": quantity if quantity is not None else unset,
2991
+ "percentage": percentage if percentage is not None else unset,
2992
+ # Never expose this: creating and executing a trade must stay separate.
2993
+ "isSendImmediately": False,
2994
+ "tradeToolSelection": trade_tool_selection,
2995
+ "tradeInstanceType": trade_instance_type,
2996
+ "tradeInstanceSubType": trade_instance_sub_type,
2997
+ }
2998
+
2999
+ res = self.api_request(f"{self.base_url}/tradeorder/trades", requests.post, json=payload)
3000
+ result = res.json()
3001
+ self._maybe_wait_for_analytics(sync)
3002
+ return result
3003
+
2787
3004
  def cash_needs_trade(
2788
3005
  self,
2789
3006
  portfolio_ids,
@@ -5179,7 +5396,8 @@ class EclipseV1(EclipseBase):
5179
5396
  Args:
5180
5397
  account_id: Internal account ID
5181
5398
  aside_cash_id: Set-aside-cash ID
5182
- payload: Set-aside DTO (request body)
5399
+ payload: Set-aside DTO (request body). May include ``isDepleteOverTime``
5400
+ (bool), the API equivalent of the UI "Deplete Over Time" checkbox.
5183
5401
  """
5184
5402
  return self.api_request(
5185
5403
  f"{self.base_url}/account/accounts/{account_id}/asidecash/{aside_cash_id}",
@@ -5744,7 +5962,8 @@ class EclipseV1(EclipseBase):
5744
5962
 
5745
5963
  Args:
5746
5964
  portfolio_id: Portfolio ID
5747
- payload: Set-aside DTO (request body)
5965
+ payload: Set-aside DTO (request body). May include ``isDepleteOverTime``
5966
+ (bool), the API equivalent of the UI "Deplete Over Time" checkbox.
5748
5967
  """
5749
5968
  return self.api_request(
5750
5969
  f"{self.base_url}/portfolio/portfolios/{portfolio_id}/asideCash",
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "orionapi"
3
- version = "2.22.0"
3
+ version = "2.24.0"
4
4
  description = "A python interface for the Orion Advisors platform web API"
5
5
  authors = ["spencerogden-dsam <67068943+spencerogden-dsam@users.noreply.github.com>"]
6
6
 
File without changes