179 const std::vector<pineforge::Bar> minutes = minute_bars();
182 std::vector<pineforge::Bar> inputs;
183 inputs.reserve(kInputs);
184 for (
int i = 0; i < kInputs; ++i) {
185 inputs.push_back(hand_aggregate(minutes,
static_cast<std::size_t
>(i) * 15, 15));
193 if (refused.error != pineforge::NativeRunSpecError::SubscriptionWithoutAuxiliaryFeed) {
194 std::cerr <<
"a finer series without a feed must be refused by name, got error "
195 <<
static_cast<int>(refused.error) <<
'\n';
198 std::printf(
"without a feed: refused, NativeRunSpecError::SubscriptionWithoutAuxiliaryFeed\n");
207 AuxiliaryFeedExample host;
208 if (host.configure_native(spec).status != pineforge::NativeSetupStatus::Applied) {
209 std::cerr <<
"configure: " << host.last_error() <<
'\n';
212 host.run(inputs.data(),
static_cast<int>(inputs.size()));
213 if (host.native_state().kind != pineforge::NativeLifecycleKind::Completed) {
214 std::cerr <<
"run: " << host.last_error() <<
'\n';
219 if (host.deliveries.size() !=
static_cast<std::size_t
>(kBuckets) || host.bars != kInputs) {
220 std::cerr <<
"expected " << kBuckets <<
" buckets over " << kInputs
221 <<
" inputs, got " << host.deliveries.size() <<
" over " << host.bars <<
'\n';
224 for (
int j = 0; j < kBuckets; ++j) {
225 const auto& delivery = host.deliveries[
static_cast<std::size_t
>(j)];
226 const pineforge::Bar want = hand_aggregate(minutes,
static_cast<std::size_t
>(j) * 5, 5);
227 if (delivery.subscription != 0 || !bars_equal(delivery.bucket, want)) {
228 std::cerr <<
"bucket " << j <<
" is not the aggregation of its five minutes\n";
233 if (delivery.bars_calculated_before != j / 3 || !delivery.accessor_matches) {
234 std::cerr <<
"bucket " << j <<
" rode on input " << delivery.bars_calculated_before
235 <<
" (expected " << (j / 3) <<
") or the pull side disagreed\n";
240 std::printf(
"buckets: %zu over %d inputs, three per input, oldest first\n",
241 host.deliveries.size(), host.bars);
242 for (
int j = 0; j < kBuckets; ++j) {
243 const auto& d = host.deliveries[
static_cast<std::size_t
>(j)];
244 std::printf(
" %02lld:%02lld o=%.2f h=%.2f l=%.2f c=%.2f %s, on input %d\n",
245 static_cast<long long>(d.bucket.timestamp / 3600000),
246 static_cast<long long>(d.bucket.timestamp / kMinute % 60),
247 d.bucket.open, d.bucket.high, d.bucket.low, d.bucket.close,
248 d.bucket.close > d.bucket.open ?
"up " :
"down",
249 d.bars_calculated_before);
254 if (host.series_at_bar.size() !=
static_cast<std::size_t
>(kInputs)) {
255 std::cerr <<
"expected one series reading per input bar\n";
258 for (
int i = 0; i < kInputs; ++i) {
259 const auto& seen = host.series_at_bar[
static_cast<std::size_t
>(i)];
260 const pineforge::Bar want = hand_aggregate(minutes,
static_cast<std::size_t
>(i) * 15 + 10, 5);
261 if (!seen || !bars_equal(*seen, want)) {
262 std::cerr <<
"native_series_bar(0) on input " << i
263 <<
" is not the last bucket that rode on it\n";
267 std::printf(
"native_series_bar(0) on each input bar: the third bucket of that input\n");
269 std::cout <<
"closed trades: " << host.trade_count() <<
'\n';
270 for (
int i = 0; i < host.trade_count(); ++i) {
271 const auto& trade = host.get_trade(i);
272 std::cout <<
" " << (trade.is_long ?
"long " :
"short")
273 <<
" qty=" << trade.qty
274 <<
" entry=" << trade.entry_price
275 <<
" exit=" << trade.exit_price
276 <<
" pnl=" << trade.pnl <<
'\n';
278 return host.trade_count() > 0 ? 0 : 1;
static void submit(struct host_state *state, uint32_t intent, double value, uint32_t trigger, double price, const char *label)