Bound a slow AI stock research task without hiding missing work
When an AI stock research task takes too long, first bound what it is allowed to investigate and what it must deliver. Record a stock limit, a fixed source plan, a maximum number of attempts and a stopping budget. At the boundary, return the calculations that were actually completed and name every missing input. Producing fewer words does not establish that the research became faster or remained complete.
The runnable example below uses fictional stocks, trusted mock providers in separate Python processes and no model or market connection. It demonstrates admission limits, real waiting timeouts and partial-result accounting. CoTrading research automation remains a future or unverified capability; this tutorial does not establish a working product scheduler or promise a company report within a fixed number of minutes.
Freeze a small research contract
Suppose the request is to compare forward price-to-earnings ratios for AAA and BBB. A third stock, CCC, is proposed later. Before fetching anything, choose a two-stock limit, a single forecast year, one currency and a consistent per-share earnings definition. In this fixture, every admitted quote is 20 and every successful EPS observation is 1, with those definitions already checked.
The required output is one row per admitted stock. A row needs a quote, an EPS observation and the resulting ratio. Source discovery, full report interpretation, management assessment and price forecasts are outside this contract. Keep an explicit exclusion for CCC; silently ignoring it would make a two-stock result appear to answer a three-stock request.
Separate fixed scope from an attempt allowance. Two sources for two stocks normally require four calls. An attempt limit permits a bounded retry after an empty response or timeout, but does not authorize adding another provider, another fiscal year or an extra stock. Every proposed expansion should create a new task version.
Set limits that control different failure modes
Use the following hypothetical configuration:
| Limit | Fixture value | What it controls |
|---|---|---|
| Admitted stocks | 2 | Research universe |
| Calls across the job | 5 | Total source attempts |
| Attempts per stock/source pair | 2 | Repeated empty or slow retrieval |
| Elapsed job budget | 6 seconds | Admission of further calls |
| Ordinary source wait | 0.8 seconds | Waiting for one mock process |
These limits are independent. A provider can consume its two attempts before the global call allowance is exhausted. A job can reach its elapsed boundary while calls remain. Count a launched attempt even when it returns no usable information. Otherwise a service that repeatedly times out can consume resources indefinitely while the dashboard still says zero successful calls.
Validate configuration before execution. The example rejects nonpositive integer limits, duplicate stock identifiers and nonfinite or nonpositive time allowances. A call budget is not a token or monetary budget: an expensive model request can cost more than several small requests. Real deployments need separate provider output, document-size and charge controls.
Measure actual steps instead of estimating from summary length
The Python performance-counter documentation supplies the elapsed-time primitive used by the fixture. Each attempted source records its start-to-return interval, stock, source, attempt and state. The report also retains total elapsed time. These measurements describe this local run, not the speed of an external research service.
Read the trace before changing the research prompt. If quote retrieval is quick but EPS requests dominate waiting, shortening the final narrative will not remove that delay. If every source is fast and calculation is slow, inspect the calculation separately. If most time is spent spawning mock processes, that overhead should not be presented as real provider latency.
Keep successful, empty, timed-out and unstarted rows separate. An empty answer has returned; a timeout has not supplied a completed observation; an unstarted call has not tested the source at all. Those differences determine whether another attempt is useful and what the reader can infer from the missing EPS.
Enforce the admission boundary before each attempt
The core loop checks both remaining time and total calls before launching work:
remaining = budget_seconds - (perf_counter() - start)
if calls >= max_calls or remaining <= 0:
state = "not_started_limit"
else:
calls += 1
response = subprocess.run(
command, timeout=min(remaining, source_timeout),
capture_output=True, text=True, check=True,
)
The complete example supplies its own trusted commands and validates returned numbers. It does not execute provider-supplied Python. A real adapter would replace those commands with a documented retrieval interface and an explicit cancellation policy. Invalid source numbers are input errors, not evidence that the stock deserves a lower research priority.
Required calculations also need a completion rule. This fixture calculates PE only when both required positive inputs were received. Its narrow calculator rejects unsupported numeric inputs rather than constructing a ratio from a guessed EPS. A production research model should additionally distinguish valid loss forecasts from unusable data and explain when PE is not an appropriate measure.
Reproduce four different outcomes
Download the complete example, use Python 3.12 or later, and run python R557.py. It uses the standard library and synthetic inputs. The normal case admits AAA and BBB, excludes CCC, makes four calls and computes PE 20 for both admitted stocks.
The call-cap case permits only two calls. AAA can finish on the recorded machine, while BBB’s price and EPS are explicitly unstarted. The empty-EPS case makes one quote attempt and two empty EPS attempts: three calls, a partial row and no PE. It does not turn the missing EPS into zero.
The slow case researches BBB alone and makes its EPS mock sleep for 0.4 seconds while allowing a 0.15-second wait per call. The observed run receives the quote and records two EPS timeouts, leaving the ratio absent. On a slower machine even a process’s startup can consume the allowance; the trace preserves that outcome rather than asserting that every apparently fast step must succeed.
Assertions check admitted scope, call counts, missing fields, absent ratios and actual timeout observations. They deliberately do not assert a universal elapsed duration. Preserve the emitted trace when comparing machines or adapter changes, because the measured timings will vary even when the accounting invariants remain correct.
Understand the timeout boundary honestly
The subprocess documentation describes termination and waiting after a timeout and notes a process-creation limitation. Accordingly, this example’s elapsed budget is an admission boundary with bounded waits, not a hard real-time guarantee. Report any overrun rather than changing the timestamp to fit the plan.
A timeout on a future or a network wait is also not a general guarantee that the underlying external activity stopped. Before adapting the design, establish whether the provider supports cancellation, whether a request can still complete remotely and whether retrying can duplicate paid work. This fixture only controls its own trusted child processes.
Hand off the completed and incomplete work
Deliver the task definition, the per-step trace and the result table together. A reviewer should reconstruct why a stock has a ratio or a missing value without reading the narrative first. Retain the quote definition, fiscal year, EPS basis and source identity with actual research data; the small numerical fixture assumes those checks instead of proving them.
Resume unfinished work as a new attempt against a preserved task version. Reuse an observation only when its identity and freshness still satisfy the contract. A newly corrected forecast or a different comparison year requires deliberate invalidation. The useful speed improvement is less unnecessary work with visible coverage, while every displayed calculation remains reproducible.
Check the completed work against the original request
Inspect the result rows and the trace together. A fast exit with two partial rows is a different deliverable from two completed ratios. Preserve call counts, missing fields and excluded stocks beside the runtime measurement so an optimization cannot pass merely by skipping required calculations. Repeat the fixture on the deployment runtime before choosing operational limits.
FAQ
Does a six-second budget guarantee a complete company study?
No. It limits this fixture’s admission and waits. Missing inputs remain missing, and operating-system overhead can exceed a requested wait.
Can I report a timeout as no analyst coverage?
No. A timed-out request has not established what the source contains. Preserve the retrieval state and inspected scope.