diff --git a/src/native_execution_consumer.cpp b/src/native_execution_consumer.cpp index f1acba9..de9194b 100644 --- a/src/native_execution_consumer.cpp +++ b/src/native_execution_consumer.cpp @@ -1064,7 +1064,9 @@ void NativeExecutionConsumer::invoke_callback(BacktestEngine& engine, const Bar& void NativeExecutionConsumer::deliver_confirmed_script(BacktestEngine& engine, const Bar& bar, const NativeCoordinate& base) { - const bool high_first = internal::bar_path_uses_high_first(bar); + // Native AUTO depends on this input, including when another legacy host + // has installed a forced path around a nested native run. + const bool high_first = std::abs(bar.high - bar.open) < std::abs(bar.open - bar.low); auto emit_match = [&](double price, int64_t time, NativePriceProvenance provenance, NativePathPhase phase) { NativeDriverPoint point; diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 8799de1..3fd4e04 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -9,6 +9,7 @@ set(TEST_SOURCES test_native_market_vertical test_native_market_vertical_contract test_native_calendar_driver_contract + test_native_auto_path test_native_host_repairs test_order_action_integration test_placement_facts diff --git a/tests/test_native_auto_path.cpp b/tests/test_native_auto_path.cpp new file mode 100644 index 0000000..f222bd5 --- /dev/null +++ b/tests/test_native_auto_path.cpp @@ -0,0 +1,57 @@ +#include +#include +#include +using namespace pineforge; +struct Native final : NativeStrategyHost { + void on_native_bar(const Bar&, const NativeDecisionContext&) override {} +}; +NativeRunSpec configuration() { + NativeRunSpec s; + s.identity={"r2-auto-path-witness",1}; s.input_tf="1"; s.script_tf="1"; + s.ticker="N";s.tickerid="TEST:N";s.type="crypto";s.currency="USD"; + s.basecurrency="USD";s.description="native";s.volumetype="base"; + s.timezone="UTC";s.session="24x7";s.initial_capital=10000; + s.point_value=1;s.account_fx=1;s.price_tick=.01;s.fee_value=0; + return s; +} +// A separate legacy host installs its own forced path in thread-local state. +// Native AUTO must remain independent while nested inside that callback. +struct Outer final : BacktestEngine { + Native& native; + Bar input{100,110,99,100,1,1736121600000LL}; + explicit Outer(Native& n, const Bar& b):native(n),input(b) {} + void on_bar(const Bar&) override { native.run(&input,1); } +}; +std::vector phases(const Native& n) { + std::vector out; + for(const auto& e:n.native_events(0)) if(e.driver) { + const auto p=e.driver->coordinate.path_phase; + if(p==NativePathPhase::High || p==NativePathPhase::Low) out.push_back(int(p)); + } + return out; +} +int run_case(int forced, const Bar& b, const std::vector& expected) { + Native alone, nested; + if(alone.configure_native(configuration()).status!=NativeSetupStatus::Applied || + nested.configure_native(configuration()).status!=NativeSetupStatus::Applied) return 1; + alone.run(&b,1); + Outer outer(nested,b); outer.set_path_order(forced); outer.run(&b,1); + const auto a=phases(alone), n=phases(nested); + const bool ok=alone.native_state().kind==NativeLifecycleKind::Completed && + nested.native_state().kind==NativeLifecycleKind::Completed && a==expected && n==a; + if(!ok) { + std::printf("FAIL forced=%d standalone:",forced);for(int x:a) std::printf(" %d",x); + std::printf(" nested:");for(int x:n) std::printf(" %d",x); + std::printf(" expected:");for(int x:expected) std::printf(" %d",x); + std::printf("\n"); + } + return ok?0:1; +} +int main() { + constexpr int64_t t=1736121600000LL; + int failures=run_case(1,{100,110,99,100,1,t},{3,2}); + failures+=run_case(2,{100,101,90,100,1,t},{2,3}); + failures+=run_case(1,{100,110,90,100,1,t},{3,2}); + std::printf("%s native AUTO isolation: 3 cases, %d failures\n",failures?"FAIL":"PASS",failures); + return failures?1:0; +}