@hoox-sh/pynets 0.3.0 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -418,6 +418,8 @@ function emitName(state: State, node: Name): string {
418
418
  if (CHART_LOCALS.has(id)) return id;
419
419
  if (state.ctx.userFuncs.has(id)) return id;
420
420
  if (state.ctx.enumTypes.has(id)) return JSON.stringify(id);
421
+ // Dataset last-bar time on every bar (interpret ctx.timenow / lastBarTime).
422
+ if (id === "timenow") return "__h.timenow(time_arr)";
421
423
  return safeIdent(id);
422
424
  }
423
425
 
@@ -540,8 +542,57 @@ const STRATEGY_QUERY_ATTRS = new Set([
540
542
  "margin_liquidation_price",
541
543
  "position_avg_price",
542
544
  "initial_capital",
545
+ "cash",
546
+ "position_entry_name",
547
+ "account_currency",
548
+ "default_entry_qty",
549
+ "max_contracts_held_all",
550
+ "max_contracts_held_long",
551
+ "max_contracts_held_short",
552
+ "wintrades",
553
+ "losstrades",
554
+ "eventrades",
555
+ "grossprofit",
556
+ "grossloss",
557
+ "avg_trade",
558
+ "avg_winning_trade",
559
+ "avg_losing_trade",
560
+ "netprofit_percent",
561
+ "openprofit_percent",
562
+ "grossprofit_percent",
563
+ "grossloss_percent",
564
+ "avg_trade_percent",
565
+ "avg_winning_trade_percent",
566
+ "avg_losing_trade_percent",
567
+ "max_drawdown",
568
+ "max_drawdown_percent",
569
+ "max_runup",
570
+ "max_runup_percent",
571
+ "percent_profitable",
572
+ "winrate",
573
+ "profitfactor",
574
+ "profit_factor",
543
575
  ]);
544
576
 
577
+ /** Nested `strategy.*` constants (interpret `strategySeriesValue`). */
578
+ const STRATEGY_NESTED_CONSTS: Record<string, string> = {
579
+ "strategy.direction.long": "long",
580
+ "strategy.direction.short": "short",
581
+ "strategy.direction.all": "all",
582
+ "strategy.oca.none": "none",
583
+ "strategy.oca.cancel": "cancel",
584
+ "strategy.oca.reduce": "reduce",
585
+ "strategy.commission.percent": "percent",
586
+ "strategy.commission.cash_per_order": "cash_per_order",
587
+ "strategy.commission.cash_per_contract": "cash_per_contract",
588
+ };
589
+
590
+ /** Nested `strategy.*` series that are not a single identifier. */
591
+ const STRATEGY_NESTED_CALLS: Record<string, string> = {
592
+ "strategy.closedtrades.first_index": "closedtrades_first_index",
593
+ "strategy.opentrades.capital_held": "capital_held",
594
+ };
595
+
545
596
  /** Namespaces used as call receivers or dotted constants — not UDT field access. */
546
597
  const ATTR_NAMESPACES = new Set([
547
598
  "ta",
@@ -652,6 +703,26 @@ const ATTR_CONSTANTS: Record<string, string | number | boolean> = {
652
703
  "hline.style_solid": "solid",
653
704
  "hline.style_dashed": "dashed",
654
705
  "hline.style_dotted": "dotted",
706
+ // Python plotting.py PlotStyle — longer than hline's "solid".
707
+ "plot.linestyle_solid": "linestyle_solid",
708
+ "plot.linestyle_dashed": "linestyle_dashed",
709
+ "plot.linestyle_dotted": "linestyle_dotted",
710
+ // Python plotting.py plot.style_* (dispatch tag 0 strings).
711
+ "plot.style_line": "style_line",
712
+ "plot.style_linebr": "style_linebr",
713
+ "plot.style_stepline": "style_stepline",
714
+ "plot.style_steplinebr": "style_steplinebr",
715
+ "plot.style_stepline_diamond": "style_stepline_diamond",
716
+ "plot.style_histogram": "style_histogram",
717
+ "plot.style_columns": "style_columns",
718
+ "plot.style_cross": "style_cross",
719
+ "plot.style_area": "style_area",
720
+ "plot.style_areabr": "style_areabr",
721
+ "plot.style_circles": "style_circles",
722
+ // Python alerts.py FREQ_* tokens.
723
+ "alert.freq_once_per_bar": "once_per_bar",
724
+ "alert.freq_once_per_bar_close": "once_per_bar_close",
725
+ "alert.freq_all": "all",
655
726
  "dayofweek.sunday": 1,
656
727
  "dayofweek.monday": 2,
657
728
  "dayofweek.tuesday": 3,
@@ -688,6 +759,8 @@ const ATTR_CONST_NS = new Set([
688
759
  "display",
689
760
  "position",
690
761
  "hline",
762
+ "plot",
763
+ "alert",
691
764
  "dayofweek",
692
765
  "month",
693
766
  ]);
@@ -847,13 +920,29 @@ function emitAttribute(state: State, node: Attribute): string {
847
920
  if (attr === "avg_price_stock") return `"stock"`;
848
921
  if (attr === "avg_price_futures") return `"futures"`;
849
922
  if (attr === "avg_price_inverse") return `"inverse"`;
850
- if (attr === "cash") return `"cash"`;
851
923
  if (attr === "fixed") return `"fixed"`;
852
924
  if (attr === "percent_of_equity") return `"percent_of_equity"`;
925
+ // `strategy.commission` the series is 0; `strategy.commission.percent` is nested.
926
+ if (attr === "commission") return "0";
853
927
  if (STRATEGY_QUERY_ATTRS.has(attr)) {
854
928
  state.ctx.usesStrategy = true;
855
929
  return `__h.strategy.${attr}()`;
856
930
  }
931
+ return "null";
932
+ }
933
+ if (node.attr === "all" && node.value.kind === "Name") {
934
+ const kind = node.value.id;
935
+ if (
936
+ kind === "line" ||
937
+ kind === "label" ||
938
+ kind === "box" ||
939
+ kind === "table" ||
940
+ kind === "polyline" ||
941
+ kind === "linefill"
942
+ ) {
943
+ state.ctx.usesDrawings = true;
944
+ return `__h.draw.all(${JSON.stringify(kind)})`;
945
+ }
857
946
  }
858
947
  if (node.value.kind === "Name") {
859
948
  const members = state.ctx.enumTypes.get(node.value.id);
@@ -863,6 +952,14 @@ function emitAttribute(state: State, node: Attribute): string {
863
952
  }
864
953
  const qn = attrQualifiedName(node);
865
954
  if (qn != null) {
955
+ const nested = STRATEGY_NESTED_CONSTS[qn];
956
+ if (nested !== undefined) return JSON.stringify(nested);
957
+ const nestedCall = STRATEGY_NESTED_CALLS[qn];
958
+ if (nestedCall != null) {
959
+ state.ctx.usesStrategy = true;
960
+ return `__h.strategy.${nestedCall}()`;
961
+ }
962
+ if (qn.startsWith("strategy.") && qn.split(".").length > 2) return "null";
866
963
  const dot = qn.indexOf(".");
867
964
  const root = dot < 0 ? qn : qn.slice(0, dot);
868
965
  if (ATTR_CONST_NS.has(root)) {