Add smart account detection - auto-block short selling for live accounts under 25k
This commit is contained in:
@@ -8,7 +8,7 @@
|
|||||||
"MIN_NOTIONAL": 1.0,
|
"MIN_NOTIONAL": 1.0,
|
||||||
"POLL_INTERVAL": 60,
|
"POLL_INTERVAL": 60,
|
||||||
"MAX_DRAWDOWN": 0.05,
|
"MAX_DRAWDOWN": 0.05,
|
||||||
"PDT_RULE": false,
|
"PDT_RULE": true,
|
||||||
"USE_TRAILING_STOP": true,
|
"USE_TRAILING_STOP": true,
|
||||||
"PROFIT_TARGET_1": 2.0,
|
"PROFIT_TARGET_1": 2.0,
|
||||||
"PROFIT_TARGET_2": 4.0,
|
"PROFIT_TARGET_2": 4.0,
|
||||||
@@ -41,7 +41,7 @@
|
|||||||
"REQUIRE_MACD_CONFIRMATION": false,
|
"REQUIRE_MACD_CONFIRMATION": false,
|
||||||
"MIN_RISK_REWARD": 2.0,
|
"MIN_RISK_REWARD": 2.0,
|
||||||
"PULLBACK_PERCENTAGE": 0.382,
|
"PULLBACK_PERCENTAGE": 0.382,
|
||||||
"ENABLE_SHORT_SELLING": false,
|
"ENABLE_SHORT_SELLING": true,
|
||||||
"RSI_BUY_MAX": 55,
|
"RSI_BUY_MAX": 55,
|
||||||
"RSI_SELL_MIN": 45,
|
"RSI_SELL_MIN": 45,
|
||||||
"RSI_SELL_MAX": 70,
|
"RSI_SELL_MAX": 70,
|
||||||
@@ -49,7 +49,7 @@
|
|||||||
"RSI_RANGE_OVERBOUGHT": 70,
|
"RSI_RANGE_OVERBOUGHT": 70,
|
||||||
"REQUIRE_MA_CROSSOVER": true,
|
"REQUIRE_MA_CROSSOVER": true,
|
||||||
"CROSSOVER_LOOKBACK": 5,
|
"CROSSOVER_LOOKBACK": 5,
|
||||||
"REQUIRE_CASH_ACCOUNT": true,
|
"REQUIRE_CASH_ACCOUNT": false,
|
||||||
"T1_SETTLEMENT_ENABLED": true,
|
"T1_SETTLEMENT_ENABLED": false,
|
||||||
"CASH_RESERVE_PCT": 0.1
|
"CASH_RESERVE_PCT": 0.0
|
||||||
}
|
}
|
||||||
|
|||||||
+44
-20
@@ -157,41 +157,65 @@ try:
|
|||||||
account = test_client.get_account()
|
account = test_client.get_account()
|
||||||
logger.info("✅ API credentials validated")
|
logger.info("✅ API credentials validated")
|
||||||
|
|
||||||
if REQUIRE_CASH_ACCOUNT:
|
equity = float(getattr(account, 'equity', 0))
|
||||||
account_type = getattr(account, 'account_blocked', False)
|
|
||||||
is_pattern_day_trader = getattr(account, 'pattern_day_trader', False)
|
|
||||||
daytrade_count = getattr(account, 'daytrade_count', 0)
|
|
||||||
|
|
||||||
account_status = getattr(account, 'status', 'UNKNOWN')
|
|
||||||
if account_status != 'ACTIVE':
|
|
||||||
logger.error(f"⚠️ Account status is {account_status}, must be ACTIVE")
|
|
||||||
sys.exit(1)
|
|
||||||
|
|
||||||
buying_power = float(getattr(account, 'buying_power', 0))
|
buying_power = float(getattr(account, 'buying_power', 0))
|
||||||
cash = float(getattr(account, 'cash', 0))
|
cash = float(getattr(account, 'cash', 0))
|
||||||
|
is_pattern_day_trader = getattr(account, 'pattern_day_trader', False)
|
||||||
|
daytrade_count = getattr(account, 'daytrade_count', 0)
|
||||||
|
account_status = getattr(account, 'status', 'UNKNOWN')
|
||||||
|
|
||||||
logger.info(f"💵 Account Type Check:")
|
is_paper_account = "paper-api.alpaca.markets" in os.getenv("APCA_API_BASE_URL", "")
|
||||||
|
|
||||||
|
logger.info(f"💵 Account Info:")
|
||||||
|
logger.info(f" Type: {'PAPER' if is_paper_account else 'LIVE'}")
|
||||||
|
logger.info(f" Equity: ${equity:.2f}")
|
||||||
logger.info(f" Cash: ${cash:.2f}")
|
logger.info(f" Cash: ${cash:.2f}")
|
||||||
logger.info(f" Buying Power: ${buying_power:.2f}")
|
logger.info(f" Buying Power: ${buying_power:.2f}")
|
||||||
logger.info(f" PDT Status: {is_pattern_day_trader}")
|
logger.info(f" PDT Status: {is_pattern_day_trader}")
|
||||||
logger.info(f" Daytrade Count: {daytrade_count}")
|
logger.info(f" Daytrade Count: {daytrade_count}")
|
||||||
|
|
||||||
if buying_power > cash * 1.5:
|
if account_status != 'ACTIVE':
|
||||||
logger.warning("⚠️ WARNING: Buying power significantly exceeds cash")
|
logger.error(f"⚠️ Account status is {account_status}, must be ACTIVE")
|
||||||
logger.warning(" This may indicate a MARGIN account, not a CASH account")
|
|
||||||
logger.warning(" Please verify your account type in Alpaca dashboard")
|
|
||||||
logger.warning(" For cash accounts under $25k, you should NOT have margin enabled")
|
|
||||||
if REQUIRE_CASH_ACCOUNT:
|
|
||||||
logger.error("⚠️ REQUIRE_CASH_ACCOUNT is True but account appears to be margin")
|
|
||||||
logger.error(" Set REQUIRE_CASH_ACCOUNT to False in config.json to bypass this check")
|
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
logger.info("✅ Cash account verified")
|
is_margin_account = buying_power > cash * 1.5
|
||||||
|
has_minimum_equity = equity >= 25000
|
||||||
|
|
||||||
|
if not is_paper_account and not has_minimum_equity:
|
||||||
|
if is_margin_account:
|
||||||
|
logger.warning("⚠️ WARNING: LIVE margin account with equity < $25,000")
|
||||||
|
logger.warning(" You should be using a CASH account to avoid PDT restrictions")
|
||||||
|
logger.warning(" Convert to cash account in your Alpaca dashboard")
|
||||||
|
|
||||||
|
if ENABLE_SHORT_SELLING:
|
||||||
|
logger.error("⚠️ SHORT SELLING DISABLED: Live account with equity < $25,000 cannot short")
|
||||||
|
logger.error(" Set ENABLE_SHORT_SELLING to False in config.json")
|
||||||
|
logger.error(" Or increase account equity to $25,000+")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
logger.info("✅ Short selling disabled for live account < $25k")
|
||||||
|
|
||||||
|
if T1_SETTLEMENT_ENABLED:
|
||||||
|
logger.info(f"✅ T+1 settlement tracking enabled")
|
||||||
|
logger.info(f" Keeping {CASH_RESERVE_PCT*100:.0f}% cash reserve for safety")
|
||||||
|
|
||||||
|
elif REQUIRE_CASH_ACCOUNT:
|
||||||
|
if is_margin_account:
|
||||||
|
logger.warning("⚠️ WARNING: Margin account detected")
|
||||||
|
logger.warning(" REQUIRE_CASH_ACCOUNT is True but buying power exceeds cash")
|
||||||
|
logger.warning(" Set REQUIRE_CASH_ACCOUNT to False in config.json for margin accounts")
|
||||||
|
|
||||||
|
logger.info("✅ Cash account mode enabled")
|
||||||
|
|
||||||
if T1_SETTLEMENT_ENABLED:
|
if T1_SETTLEMENT_ENABLED:
|
||||||
logger.info("✅ T+1 settlement tracking enabled")
|
logger.info("✅ T+1 settlement tracking enabled")
|
||||||
logger.info(f" Keeping {CASH_RESERVE_PCT*100:.0f}% cash reserve for safety")
|
logger.info(f" Keeping {CASH_RESERVE_PCT*100:.0f}% cash reserve for safety")
|
||||||
|
|
||||||
|
if is_paper_account:
|
||||||
|
logger.info("📝 Paper trading account - all restrictions relaxed")
|
||||||
|
elif has_minimum_equity:
|
||||||
|
logger.info(f"✅ Equity ${equity:.2f} >= $25,000 - full trading enabled")
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f"⚠️ Invalid API credentials: {e}")
|
logger.error(f"⚠️ Invalid API credentials: {e}")
|
||||||
logger.error(" Please check your .env file and ensure your Alpaca API keys are correct")
|
logger.error(" Please check your .env file and ensure your Alpaca API keys are correct")
|
||||||
|
|||||||
Reference in New Issue
Block a user