fix(simple): prefer available user alpaca creds

This commit is contained in:
root 2026-05-06 06:40:49 +00:00
parent b690f26a28
commit dad47fc13d
2 changed files with 47 additions and 19 deletions

View File

@ -101,6 +101,28 @@ const computeSimpleProfitTargetPrice = (entryPrice: number, entry: ManualEntryRe
return Number((entryPrice * (1 + (threshold / 100))).toFixed(4));
};
const resolvePreferredUserAlpacaCredentials = (user: {
ALPACA_API_KEY?: string;
ALPACA_SECRET_KEY?: string;
REAL_ALPACA_API_KEY?: string;
REAL_ALPACA_SECRET_KEY?: string;
}): { key: string; secret: string; source: 'paper' | 'live' | 'none' } => {
const paperKey = String(user.ALPACA_API_KEY || '').trim();
const paperSecret = String(user.ALPACA_SECRET_KEY || '').trim();
const liveKey = String(user.REAL_ALPACA_API_KEY || '').trim();
const liveSecret = String(user.REAL_ALPACA_SECRET_KEY || '').trim();
if (config.PAPER_TRADING) {
if (paperKey && paperSecret) return { key: paperKey, secret: paperSecret, source: 'paper' };
if (liveKey && liveSecret) return { key: liveKey, secret: liveSecret, source: 'live' };
} else {
if (liveKey && liveSecret) return { key: liveKey, secret: liveSecret, source: 'live' };
if (paperKey && paperSecret) return { key: paperKey, secret: paperSecret, source: 'paper' };
}
return { key: '', secret: '', source: 'none' };
};
async function main() {
logger.info(`Starting ${config.PRODUCT_ID} trading backend...`);
validateConfig();
@ -137,8 +159,9 @@ async function main() {
// --- 1. Identify Primary Key (for Data Fetching) ---
const isPlaceholder = (val: string) => !val || val === 'your_key' || val === 'your_secret';
const primaryAlpacaKey = (!isPlaceholder(config.ALPACA_API_KEY) ? config.ALPACA_API_KEY : (users.length > 0 ? (config.PAPER_TRADING ? users[0].ALPACA_API_KEY : users[0].REAL_ALPACA_API_KEY) : ''));
const primaryAlpacaSecret = (!isPlaceholder(config.ALPACA_API_SECRET) ? config.ALPACA_API_SECRET : (users.length > 0 ? (config.PAPER_TRADING ? users[0].ALPACA_SECRET_KEY : users[0].REAL_ALPACA_SECRET_KEY) : ''));
const preferredPrimaryUserCredentials = users.length > 0 ? resolvePreferredUserAlpacaCredentials(users[0]) : { key: '', secret: '', source: 'none' as const };
const primaryAlpacaKey = !isPlaceholder(config.ALPACA_API_KEY) ? config.ALPACA_API_KEY : preferredPrimaryUserCredentials.key;
const primaryAlpacaSecret = !isPlaceholder(config.ALPACA_API_SECRET) ? config.ALPACA_API_SECRET : preferredPrimaryUserCredentials.secret;
logger.info(`🚨 Bot Initialized for ${config.SYMBOLS.length} Symbols: ${config.SYMBOLS.join(', ')}`);
@ -237,14 +260,12 @@ async function main() {
const ctx = getSimpleWorkerContext(entry);
if (!ctx) continue;
const currentPrice = resolveSimpleMarketPrice(entry);
if (!(currentPrice && currentPrice > 0)) continue;
if (shouldArmSimpleBuy(entry)) {
const currentPrice = resolveSimpleMarketPrice(entry) ?? toPositiveNumber(entry.reference_price);
const triggerPrice = computeSimpleBuyTriggerPrice(entry);
const desiredQty = toPositiveNumber(entry.quantity);
const threshold = toNonNegativeNumber(entry.drop_threshold_for_buy);
if (!triggerPrice || !desiredQty) continue;
if (!triggerPrice || !desiredQty || !(currentPrice && currentPrice > 0)) continue;
if (currentPrice > triggerPrice) continue;
const result = await ctx.manualTrader.executeRequest(
@ -272,6 +293,9 @@ async function main() {
continue;
}
const currentPrice = resolveSimpleMarketPrice(entry);
if (!(currentPrice && currentPrice > 0)) continue;
if (isSimpleSubmittedStatus(entry.status)) {
await bindSimpleBoughtPosition(entry, ctx);
continue;
@ -458,8 +482,9 @@ async function main() {
users.push(user);
}
const userKey = config.PAPER_TRADING ? user.ALPACA_API_KEY : user.REAL_ALPACA_API_KEY;
const userSecret = config.PAPER_TRADING ? user.ALPACA_SECRET_KEY : user.REAL_ALPACA_SECRET_KEY;
const preferredCredentials = resolvePreferredUserAlpacaCredentials(user);
const userKey = preferredCredentials.key;
const userSecret = preferredCredentials.secret;
if (!userKey || !userSecret) {
logger.warn(`⚠️ User ${user.email} missing keys for profile ${profile.name}. Skipping.`);
@ -540,8 +565,9 @@ async function main() {
// Fallback to one-per-user if no profiles table entries exist
logger.info(`👥 No specific profiles found. Falling back to multi-user default...`);
for (const user of users) {
const userKey = config.PAPER_TRADING ? user.ALPACA_API_KEY : user.REAL_ALPACA_API_KEY;
const userSecret = config.PAPER_TRADING ? user.ALPACA_SECRET_KEY : user.REAL_ALPACA_SECRET_KEY;
const preferredCredentials = resolvePreferredUserAlpacaCredentials(user);
const userKey = preferredCredentials.key;
const userSecret = preferredCredentials.secret;
if (!userKey || !userSecret) continue;

View File

@ -156,18 +156,20 @@ interface AlpacaCredentials {
async function getUserExecutionAlpacaCredentials(userId: string): Promise<AlpacaCredentials> {
const profile = await getCurrentUserProfile(userId);
const key = String(config.PAPER_TRADING ? profile.ALPACA_API_KEY || '' : profile.REAL_ALPACA_API_KEY || '').trim();
const secret = String(config.PAPER_TRADING ? profile.ALPACA_SECRET_KEY || '' : profile.REAL_ALPACA_SECRET_KEY || '').trim();
const paperKey = String(profile.ALPACA_API_KEY || '').trim();
const paperSecret = String(profile.ALPACA_SECRET_KEY || '').trim();
const liveKey = String(profile.REAL_ALPACA_API_KEY || '').trim();
const liveSecret = String(profile.REAL_ALPACA_SECRET_KEY || '').trim();
if (!key || !secret) {
throw new MissingServiceConfigError(
config.PAPER_TRADING
? 'User Alpaca paper credentials are not configured'
: 'User Alpaca live credentials are not configured'
);
if (config.PAPER_TRADING) {
if (paperKey && paperSecret) return { key: paperKey, secret: paperSecret };
if (liveKey && liveSecret) return { key: liveKey, secret: liveSecret };
} else {
if (liveKey && liveSecret) return { key: liveKey, secret: liveSecret };
if (paperKey && paperSecret) return { key: paperKey, secret: paperSecret };
}
return { key, secret };
throw new MissingServiceConfigError('User Alpaca credentials are not configured');
}
async function getUserMarketDataAlpacaCredentials(userId: string): Promise<AlpacaCredentials> {