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

View File

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