Skip to content

Learn

Stock Strategy Development

Diagnose generated stock strategy import and construction failures

When a generated stock strategy produces no signals because Python cannot load it, diagnose the loading stages before changing trading thresholds. Parse the source, import its module, locate the expected class, construct it with the required interface and only then call the generator. Each boundary has different evidence and a different repair.

This guide builds five tiny trusted source strings to reproduce syntax, self-import, top-level execution and constructor failures, followed by a working version. The example runs no external service and uses no account credentials. It is a local diagnosis exercise, not a sandbox for arbitrary generated programs. CoTrading strategy import tooling remains planned or unverified.

Preserve the failing artifact and interface

Save the exact source, Python version, filename, import path and traceback before editing. A generated class may work in a notebook because a previous cell supplied a global variable while failing when loaded as a fresh module. Record the actual loader’s expectations: module name, class name, zero-argument construction and the shape of the input to generate.

For this exercise the module is signal_engine, the class is SignalEngine, construction requires no supplied arguments, and generate receives a list of completed closes. These are teaching interface choices. They are not a claim that every framework uses the same input shape. A real integration must inspect its own interface rather than paste this fixture into an unknown loader.

Class discovery deserves its own check. Verify that the expected attribute exists, is a class and exposes a callable method before assuming an empty output is a legitimate trading decision. A renamed class or a class defined only inside a main guard may import successfully but still fail discovery. Report the missing interface directly instead of moving on to a fabricated signal count.

Stop at syntax failure first

The source class SignalEngine(: cannot be parsed. Python’s AST documentation explains the parse operation used by the fixture. Parsing identifies a syntax error without executing the module body. Preserve line and column information and repair the malformed declaration before investigating runtime configuration.

Successful parsing establishes only grammatical validity. It does not establish that imports resolve, names exist or constructors can run. Avoid reporting “strategy validated” after this stage. A file can contain perfectly valid Python that raises an exception as soon as it is imported, and that is exactly the next independent failure case.

Reproduce the self-import cycle

Suppose signal_engine.py begins with from signal_engine import SignalEngine, followed by the class definition it intends to import. The file is asking its own partially initialized module for a name that has not yet been bound. In this fixture the result is an import error, before any market data or signal logic is reached.

Python’s import-system reference describes module initialization and the module cache. Read the complete traceback to distinguish this self-reference from an actually missing dependency. Installing an unrelated package with a matching name does not repair the circular structure and may obscure which module was loaded.

Remove the self-import when the class is defined in that file. If a shared interface genuinely belongs in another module, place it in a separate dependency and import from there. Confirm the resolved module path in the integration environment, because a local file can shadow an installed package. Keep the repair limited to the evidenced cause rather than rewriting the strategy’s economic rule.

Separate import-time work from generator work

A top-level raise RuntimeError demonstrates a different mechanism: the module is found, but executing its body fails. Real examples might connect to a service, read a configuration file or calculate a result at import time. Moving such work into an explicit callable makes loading distinguishable from data acquisition and evaluation.

For an optional demonstration entry point, use a main guard so importing the class does not run the demonstration. Still inspect decorators, class bodies and default expressions, which can execute during import or definition. A main guard around the last few lines does not neutralize earlier top-level effects. Verify the fresh import rather than only rereading the edited text.

The fixture intentionally raises a harmless exception rather than contacting a service. It proves that the diagnostic can label this stage; it does not test a network provider, environment variable or external credential. Do not “fix” an import by supplying a real secret when the purpose is a self-contained rule test.

Check construction as a separate boundary

A class with __init__(self, window) can import cleanly but fails when the loader calls SignalEngine() without arguments. That is a constructor contract mismatch. Decide whether the framework should inject a parameter object or the class should provide an explicit default. Changing the loader and class independently can otherwise create two incompatible conventions.

The corrected fixture uses window=3, stores it on the instance and computes a trailing comparison from the supplied closes. Production parameter validation should reject nonpositive or inappropriate values before evaluating data. A default chosen merely to avoid an exception still needs to match the approved strategy specification; a constructor repair must not silently change a required 120-day rule to three days.

For the fixed three-close teaching rule, input [10, 10, 12] gives [0, 0, 1]. The first two rows lack the window, and twelve exceeds the mean of all three observations. This verifies a real call after construction. Import success alone would not catch a method with the wrong signature or a body that immediately fails.

Run the independent reproduction pack

The standard-library artifact is docs/growth/research/round-5/examples/R580.py. It creates an isolated temporary directory, writes one trusted fixture at a time and launches a fresh Python process with bytecode writing disabled. A short timeout bounds accidental hangs in these known sources. The import command performs the same small sequence each time:

import signal_engine
engine = signal_engine.SignalEngine()
print(engine.generate([10, 10, 12]))

Run python docs/growth/research/round-5/examples/R580.py. Assertions expect parse:SyntaxError, import:ImportError, import:RuntimeError, construct:TypeError and finally [0, 0, 1]. The self-import case and required-constructor case are independent counterexamples: one fails before class initialization, the other after successful import. Their remedies should not be combined into a vague “Python issue.”

Close the issue with evidence and limits

Keep the original traceback, minimal reproduction, exact patch and successful fresh-process output. Then test the real data interface with a fixed local input. If loading succeeds but later signal values are wrong, move to a separate logic investigation rather than claiming the loader repair verified strategy correctness. Recheck after dependency, Python or loader-interface changes.

A subprocess and static parsing do not provide a security boundary against arbitrary source. This exercise executes only strings authored inside the fixture. Untrusted code requires a separately designed execution environment with resource and capability controls. The practical acceptance claim remains narrow: these four known pre-signal failures are reproducible, distinguishable and repaired without external connections, and the corrected class completes one deterministic generation call.

Download the complete example. Save it as R580.py and run python R580.py with Python 3.12 or later. It uses only the standard library and synthetic data.

Keep stage labels stable when the traceback changes

Do not rely on the complete human-readable exception sentence as the only classification key. Python releases and dependency versions can change wording while leaving the failed boundary unchanged. Preserve exception type, stage, source location and the original stderr, then compare those structured fields. A missing method discovered after successful construction should receive a generation-interface label rather than be folded into the earlier constructor case.

Use a fresh process for the final reproduction because an already imported module can hide loading behavior through the module cache. Keep the source path and the executable path in the report. If the real environment still fails while the minimal fixed source passes, compare dependency resolution and loader arguments next; do not claim the original incident is resolved solely from the isolated fixture. The pack establishes an ordered diagnostic technique and known repairs. Closing an actual integration issue requires one observed successful import, construction and generation call in that integration’s own approved interface.

FAQ

Should I change the trading threshold when import fails?

No. The generator has not run, so its threshold cannot explain the loading exception.

Does successful parsing make generated code safe?

No. Parsing checks grammar, while import and execution can still perform arbitrary actions.