ZhuLinsen/daily_stock_analysis · error · DuplicateTaskError

股票 ${stockCode} 正在分析中

Error message

股票 ${stockCode} 正在分析中

What it means

Raised during quantity replay (portfolio_service.py:757) when a trade event has quantity <= 0 (null coerces to 0.0). The replay's ledger semantics require positive quantities, so a corrupt or zero-quantity trade row aborts the whole position computation with validation_error.

Source

Thrown at apps/dsa-web/src/api/analysis.ts:94

    const response = await apiClient.post<Record<string, unknown>>(
      '/api/v1/analysis/analyze',
      requestData,
      {
        // Allow 202 accepted responses in addition to standard success codes.
        validateStatus: (status) => status === 200 || status === 202 || status === 409,
      }
    );

    // Handle duplicate submission compatibility.
    if (response.status === 409) {
      const errorData = toCamelCase<{
        error: string;
        message: string;
        stockCode: string;
        existingTaskId: string;
      }>(response.data);
      throw new DuplicateTaskError(errorData.stockCode, errorData.existingTaskId, errorData.message);
    }

    return toCamelCase<AnalyzeAsyncResponse>(response.data);
  },

  /**
   * Trigger market review in background mode.
   */
  triggerMarketReview: async (data: MarketReviewRequest = {}): Promise<MarketReviewAccepted> => {
    const response = await apiClient.post<Record<string, unknown>>(
      '/api/v1/analysis/market-review',
      {
        send_notification: data.sendNotification ?? true,
        report_language: data.reportLanguage,
        ...(data.regions !== undefined && { region: serializeMarketReviewRegions(data.regions) }),
      },
      {
        validateStatus: (status) => status === 202 || status === 409,

View on GitHub (pinned to 5159bd72e8)

Solutions

  1. Locate the offending trade: query trades for the symbol where quantity IS NULL or <= 0 and fix or delete the row
  2. Re-insert valid trades through add_trade, which validates quantity at write time
  3. Fix the importer to fail on blank quantity instead of defaulting to 0
  4. Add a DB-level CHECK (quantity > 0) or a periodic audit query

Example fix

# before
svc.add_trade(account_id=1, symbol="AAPL", side="buy", quantity=0, price=100.0, ...)
# after
svc.add_trade(account_id=1, symbol="AAPL", side="buy", quantity=10, price=100.0, ...)
Defensive patterns

Strategy: validation

Validate before calling

def trade_qty_ok(qty):
    return qty is not None and qty > 0

Type guard

from numbers import Real

def is_positive_quantity(value: Real | None) -> bool:
    return value is not None and float(value) > 0.0

Try / catch

try:
    svc.get_snapshot(account_id=a)
except ValueError as exc:
    if "Invalid trade quantity" in str(exc):
        repair_or_delete_bad_trade_rows(a); svc.get_snapshot(account_id=a)
    else:
        raise

Prevention

When it happens

Trigger: A trades row with quantity = 0, negative, or NULL reaching the replay; test rows inserted directly into the DB; importer writing 0 when the source field is missing; float('-inf')/NaN coerced through float() to a non-positive value.

Common situations: Direct database seeding in dev/test that skips service validation; CSV import with a blank quantity column parsed as 0; fee-only rows mistakenly imported as trades with zero quantity; refactors of the write path that forgot the positivity check.

Related errors


AI-assisted analysis of ZhuLinsen/daily_stock_analysis@5159bd72e8 (2026-08-15). Data as JSON: /api/errors/608764d6c3a92488. Report an issue: GitHub.