Manually cleanup the slop
This commit is contained in:
@@ -8,9 +8,9 @@ from dataclasses import dataclass
|
|||||||
from typing import Any
|
from typing import Any
|
||||||
|
|
||||||
from alpaca.trading.client import TradingClient
|
from alpaca.trading.client import TradingClient
|
||||||
from alpaca.trading.models import Position
|
from alpaca.trading.models import Order, Position, TradeAccount
|
||||||
from alpaca.trading.requests import GetOrdersRequest
|
from alpaca.trading.requests import GetOrdersRequest
|
||||||
from alpaca.trading.enums import QueryOrderStatus
|
from alpaca.trading.enums import OrderType, QueryOrderStatus
|
||||||
from dotenv import load_dotenv
|
from dotenv import load_dotenv
|
||||||
|
|
||||||
load_dotenv()
|
load_dotenv()
|
||||||
@@ -57,21 +57,6 @@ def _string_to_float(value: Any, default: float = 0.0) -> float:
|
|||||||
return default
|
return default
|
||||||
|
|
||||||
|
|
||||||
def _get_attribute(obj: Any, *names: str, default: Any = None) -> Any:
|
|
||||||
if obj is None:
|
|
||||||
return default
|
|
||||||
if isinstance(obj, dict):
|
|
||||||
for name in names:
|
|
||||||
if name in obj:
|
|
||||||
return obj[name]
|
|
||||||
return default
|
|
||||||
|
|
||||||
for name in names:
|
|
||||||
if hasattr(obj, name):
|
|
||||||
return getattr(obj, name)
|
|
||||||
return default
|
|
||||||
|
|
||||||
|
|
||||||
def create_alpaca_trading_client(
|
def create_alpaca_trading_client(
|
||||||
api_key: str | None = None,
|
api_key: str | None = None,
|
||||||
secret_key: str | None = None,
|
secret_key: str | None = None,
|
||||||
@@ -85,34 +70,22 @@ def create_alpaca_trading_client(
|
|||||||
return TradingClient(api_key, secret_key, paper=paper)
|
return TradingClient(api_key, secret_key, paper=paper)
|
||||||
|
|
||||||
|
|
||||||
def _extract_unfilled_qty(order: Any) -> float:
|
def _extract_order_limit_price(order: Order) -> float | None:
|
||||||
qty = _string_to_float(
|
value = order.limit_price
|
||||||
_get_attribute(order, "qty", "quantity", "order_qty", default=0)
|
|
||||||
)
|
|
||||||
filled = _string_to_float(
|
|
||||||
_get_attribute(order, "filled_qty", "filled_quantity", default=0)
|
|
||||||
)
|
|
||||||
return max(qty - filled, 0.0)
|
|
||||||
|
|
||||||
|
|
||||||
def _extract_order_limit_price(order: Any) -> float | None:
|
|
||||||
value = _get_attribute(order, "limit_price", "limitPrice", default=None)
|
|
||||||
if value is None:
|
if value is None:
|
||||||
return None
|
return None
|
||||||
price = _string_to_float(value, default=None)
|
price = _string_to_float(value, default=0.0)
|
||||||
return price if price is not None and price > 0 else None
|
return price if price is not None and price > 0 else None
|
||||||
|
|
||||||
|
|
||||||
def _build_order_summary(order: Any) -> AlpacaOrderSummary:
|
def _build_order_summary(order: Order) -> AlpacaOrderSummary:
|
||||||
symbol = str(_get_attribute(order, "symbol", "asset_symbol", default=DEFAULT_SYMBOL)).upper()
|
symbol = str(order.symbol).upper()
|
||||||
side = str(_get_attribute(order, "side", default="buy")).lower()
|
side = str(order.side).lower()
|
||||||
qty = _string_to_float(_get_attribute(order, "qty", "quantity", default=0))
|
qty = _string_to_float(order.qty or "0.0")
|
||||||
filled_qty = _string_to_float(
|
filled_qty = _string_to_float(order.filled_qty or "0.0")
|
||||||
_get_attribute(order, "filled_qty", "filled_quantity", default=0)
|
|
||||||
)
|
|
||||||
limit_price = _extract_order_limit_price(order)
|
limit_price = _extract_order_limit_price(order)
|
||||||
order_type = str(_get_attribute(order, "type", default="unknown"))
|
order_type = order.type or OrderType.MARKET
|
||||||
status = str(_get_attribute(order, "status", default="unknown")).lower()
|
status = order.status or QueryOrderStatus.OPEN
|
||||||
|
|
||||||
return AlpacaOrderSummary(
|
return AlpacaOrderSummary(
|
||||||
symbol=symbol,
|
symbol=symbol,
|
||||||
@@ -126,23 +99,16 @@ def _build_order_summary(order: Any) -> AlpacaOrderSummary:
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def _find_spy_position(positions: list[Any], symbol: str = DEFAULT_SYMBOL) -> tuple[float, float, float | None]:
|
def _find_spy_position(positions: list[Position], symbol: str = DEFAULT_SYMBOL) -> tuple[float, float, float | None]:
|
||||||
normalized = symbol.upper()
|
normalized = symbol.upper()
|
||||||
for position in positions:
|
for position in positions:
|
||||||
position_symbol = str(
|
position_symbol = position.symbol.upper()
|
||||||
_get_attribute(position, "symbol", "asset_symbol", default="")
|
|
||||||
).upper()
|
|
||||||
if position_symbol != normalized:
|
if position_symbol != normalized:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
quantity = _string_to_float(_get_attribute(position, "qty", "quantity", default=0))
|
quantity = _string_to_float(position.qty or "0.0")
|
||||||
market_value = _string_to_float(
|
market_value = _string_to_float(position.market_value or "0.0")
|
||||||
_get_attribute(position, "market_value", "marketValue", default=0)
|
avg_entry_price = _string_to_float(position.avg_entry_price)
|
||||||
)
|
|
||||||
avg_entry_price = _string_to_float(
|
|
||||||
_get_attribute(position, "avg_entry_price", "avgEntryPrice", default=None),
|
|
||||||
default=None,
|
|
||||||
)
|
|
||||||
return quantity, market_value, avg_entry_price
|
return quantity, market_value, avg_entry_price
|
||||||
|
|
||||||
return 0.0, 0.0, None
|
return 0.0, 0.0, None
|
||||||
@@ -155,12 +121,12 @@ def _safe_ratio(numerator: float, denominator: float) -> float | None:
|
|||||||
|
|
||||||
|
|
||||||
def summarize_alpaca_portfolio(
|
def summarize_alpaca_portfolio(
|
||||||
account: Any,
|
account: TradeAccount,
|
||||||
positions: list[Position],
|
positions: list[Position],
|
||||||
open_orders: list[Any],
|
open_orders: list[Order],
|
||||||
symbol: str = DEFAULT_SYMBOL,
|
symbol: str = DEFAULT_SYMBOL,
|
||||||
) -> AlpacaPortfolioSummary:
|
) -> AlpacaPortfolioSummary:
|
||||||
cash = _string_to_float(_get_attribute(account, "cash", default=0.0))
|
cash = _string_to_float(account.cash or "0.0")
|
||||||
spy_quantity, spy_market_value, spy_avg_entry_price = _find_spy_position(
|
spy_quantity, spy_market_value, spy_avg_entry_price = _find_spy_position(
|
||||||
positions, symbol=symbol
|
positions, symbol=symbol
|
||||||
)
|
)
|
||||||
@@ -220,6 +186,8 @@ def fetch_alpaca_portfolio_summary(
|
|||||||
paper=paper,
|
paper=paper,
|
||||||
)
|
)
|
||||||
account = client.get_account()
|
account = client.get_account()
|
||||||
|
if not isinstance(account, TradeAccount):
|
||||||
|
raise TypeError(f"Expected account to be a TradeAccount but got: {type(account)}")
|
||||||
positions = client.get_all_positions()
|
positions = client.get_all_positions()
|
||||||
if not isinstance(positions, list):
|
if not isinstance(positions, list):
|
||||||
raise TypeError(f"Expected positions to be a list but got: {type(positions)}")
|
raise TypeError(f"Expected positions to be a list but got: {type(positions)}")
|
||||||
|
|||||||
Reference in New Issue
Block a user