Fix scale out for small positions and add exception handling to order placement

This commit is contained in:
justin committed 2026-02-04 16:31:50 -07:00
1 parent 122f719b8d
commit 55f3e59d0b
2 files changed
+44 -36

No files matched your search

+40 -36
View File
@@ -55,41 +55,45 @@ class AlpacaClient:
return self.api.get_position(symbol)
def place_order(self, symbol, side, notional, limit_price, limit_order_timeout):
quote = self.get_latest_quote(symbol)
if quote is None:
return None
bid_price = getattr(quote, 'bid_price', None)
ask_price = getattr(quote, 'ask_price', None)
if limit_price:
price_source = limit_price
else:
price_source = bid_price if side == "buy" else ask_price
if price_source is None or price_source <= 0:
return None
shares = int(notional / price_source)
if shares == 0:
return None
if limit_price:
order = self.submit_order(symbol=symbol, qty=shares, side=side, type="limit", limit_price=round(limit_price, 2), time_in_force="day")
start = time.time()
while time.time() - start < limit_order_timeout:
status = self.get_order(order.id)
if status.status == "filled":
return float(status.filled_avg_price)
if status.status in {"cancelled", "expired", "rejected"}:
return None
time.sleep(2)
self.cancel_order(order.id)
return None
order = self.submit_order(symbol=symbol, qty=shares, side=side, type="market", time_in_force="day")
status = self.get_order(order.id)
timeout = 30
start_time = time.time()
while status.status not in {"filled", "cancelled", "expired", "rejected"}:
if time.time() - start_time > timeout:
try:
quote = self.get_latest_quote(symbol)
if quote is None:
return None
time.sleep(0.5)
bid_price = getattr(quote, 'bid_price', None)
ask_price = getattr(quote, 'ask_price', None)
if limit_price:
price_source = limit_price
else:
price_source = bid_price if side == "buy" else ask_price
if price_source is None or price_source <= 0:
return None
shares = int(notional / price_source)
if shares == 0:
return None
if limit_price:
order = self.submit_order(symbol=symbol, qty=shares, side=side, type="limit", limit_price=round(limit_price, 2), time_in_force="day")
start = time.time()
while time.time() - start < limit_order_timeout:
status = self.get_order(order.id)
if status.status == "filled":
return float(status.filled_avg_price)
if status.status in {"cancelled", "expired", "rejected"}:
return None
time.sleep(2)
self.cancel_order(order.id)
return None
order = self.submit_order(symbol=symbol, qty=shares, side=side, type="market", time_in_force="day")
status = self.get_order(order.id)
if status.status == "filled":
return float(status.filled_avg_price)
return None
timeout = 30
start_time = time.time()
while status.status not in {"filled", "cancelled", "expired", "rejected"}:
if time.time() - start_time > timeout:
return None
time.sleep(0.5)
status = self.get_order(order.id)
if status.status == "filled":
return float(status.filled_avg_price)
return None
except Exception as e:
print(f"Order placement error: {e}")
return None
+4
View File
@@ -763,6 +763,10 @@ def scale_out_profit_taking(symbol, entry_price, current_price, stop_loss, posit
position_state.target_1_hit = True
logger.info(f"💰 Partial profit @ {profit_pct:.2f}% ({half_qty} shares)")
debug_print(f"Partial profit taken: {half_qty} shares @ {profit_pct:.2f}%")
else:
position_state.target_1_hit = True
logger.info(f"💰 Target 1 reached @ {profit_pct:.2f}% (position too small to scale)")
debug_print(f"Position size {qty} too small for partial exit, holding for target 2")
if profit_pct >= target_2_pct:
qty = current_position_qty(symbol)