@senpi/runtime 1.0.95-dev.feat-dsl-backend-int.20260416023008 → 1.0.95-dev.runtime-phase-2.20260416194608

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.
Files changed (285) hide show
  1. package/README.md +72 -0
  2. package/dist/actions/action-runtime-module.d.ts +55 -0
  3. package/dist/actions/action-runtime-module.d.ts.map +1 -0
  4. package/dist/actions/action-runtime-module.js +444 -0
  5. package/dist/actions/action-runtime-module.js.map +1 -0
  6. package/dist/actions/close-position/close-position.action.d.ts +1 -0
  7. package/dist/actions/close-position/close-position.action.d.ts.map +1 -1
  8. package/dist/actions/close-position/close-position.action.js +55 -20
  9. package/dist/actions/close-position/close-position.action.js.map +1 -1
  10. package/dist/actions/decision-engine.d.ts.map +1 -1
  11. package/dist/actions/decision-engine.js +5 -0
  12. package/dist/actions/decision-engine.js.map +1 -1
  13. package/dist/actions/llm-decision/shared.d.ts +1 -1
  14. package/dist/actions/llm-decision/shared.d.ts.map +1 -1
  15. package/dist/actions/llm-decision/shared.js +1 -1
  16. package/dist/actions/llm-decision/shared.js.map +1 -1
  17. package/dist/actions/notifications/formatter.d.ts +39 -0
  18. package/dist/actions/notifications/formatter.d.ts.map +1 -0
  19. package/dist/actions/notifications/formatter.js +68 -0
  20. package/dist/actions/notifications/formatter.js.map +1 -0
  21. package/dist/actions/notifications/index.d.ts +37 -0
  22. package/dist/actions/notifications/index.d.ts.map +1 -0
  23. package/dist/actions/notifications/index.js +89 -0
  24. package/dist/actions/notifications/index.js.map +1 -0
  25. package/dist/actions/open-position/open-position.action.d.ts +1 -0
  26. package/dist/actions/open-position/open-position.action.d.ts.map +1 -1
  27. package/dist/actions/open-position/open-position.action.js +132 -27
  28. package/dist/actions/open-position/open-position.action.js.map +1 -1
  29. package/dist/actions/open-position/resolve-margin.d.ts +22 -0
  30. package/dist/actions/open-position/resolve-margin.d.ts.map +1 -0
  31. package/dist/actions/open-position/resolve-margin.js +30 -0
  32. package/dist/actions/open-position/resolve-margin.js.map +1 -0
  33. package/dist/actions/position-tracker/position-tracker.action.d.ts.map +1 -1
  34. package/dist/actions/position-tracker/position-tracker.action.js +4 -1
  35. package/dist/actions/position-tracker/position-tracker.action.js.map +1 -1
  36. package/dist/actions/store/action-store.d.ts +45 -0
  37. package/dist/actions/store/action-store.d.ts.map +1 -0
  38. package/dist/actions/store/action-store.js +127 -0
  39. package/dist/actions/store/action-store.js.map +1 -0
  40. package/dist/actions/store/index.d.ts +11 -0
  41. package/dist/actions/store/index.d.ts.map +1 -0
  42. package/dist/actions/store/index.js +9 -0
  43. package/dist/actions/store/index.js.map +1 -0
  44. package/dist/actions/store/paths.d.ts +15 -0
  45. package/dist/actions/store/paths.d.ts.map +1 -0
  46. package/dist/actions/store/paths.js +29 -0
  47. package/dist/actions/store/paths.js.map +1 -0
  48. package/dist/actions/store/types.d.ts +114 -0
  49. package/dist/actions/store/types.d.ts.map +1 -0
  50. package/dist/actions/store/types.js +48 -0
  51. package/dist/actions/store/types.js.map +1 -0
  52. package/dist/actions/tracking-helpers.d.ts +13 -0
  53. package/dist/actions/tracking-helpers.d.ts.map +1 -0
  54. package/dist/actions/tracking-helpers.js +47 -0
  55. package/dist/actions/tracking-helpers.js.map +1 -0
  56. package/dist/actions/types.d.ts +8 -0
  57. package/dist/actions/types.d.ts.map +1 -1
  58. package/dist/cli/guide-commands.d.ts.map +1 -1
  59. package/dist/cli/guide-commands.js +105 -3
  60. package/dist/cli/guide-commands.js.map +1 -1
  61. package/dist/cli/senpi-commands.d.ts.map +1 -1
  62. package/dist/cli/senpi-commands.js +428 -1
  63. package/dist/cli/senpi-commands.js.map +1 -1
  64. package/dist/constants/order-types.d.ts +7 -0
  65. package/dist/constants/order-types.d.ts.map +1 -0
  66. package/dist/constants/order-types.js +6 -0
  67. package/dist/constants/order-types.js.map +1 -0
  68. package/dist/context/interpolate.d.ts +6 -2
  69. package/dist/context/interpolate.d.ts.map +1 -1
  70. package/dist/context/interpolate.js +6 -2
  71. package/dist/context/interpolate.js.map +1 -1
  72. package/dist/context/types.d.ts +8 -1
  73. package/dist/context/types.d.ts.map +1 -1
  74. package/dist/context/types.js +8 -1
  75. package/dist/context/types.js.map +1 -1
  76. package/dist/dsl/config/exit-block.d.ts +7 -0
  77. package/dist/dsl/config/exit-block.d.ts.map +1 -1
  78. package/dist/dsl/config/parse-plugin-config.d.ts.map +1 -1
  79. package/dist/dsl/config/parse-plugin-config.js +27 -1
  80. package/dist/dsl/config/parse-plugin-config.js.map +1 -1
  81. package/dist/dsl/config/unknown-keys.d.ts.map +1 -1
  82. package/dist/dsl/config/unknown-keys.js +3 -1
  83. package/dist/dsl/config/unknown-keys.js.map +1 -1
  84. package/dist/dsl/monitor/create-monitor.d.ts +4 -0
  85. package/dist/dsl/monitor/create-monitor.d.ts.map +1 -1
  86. package/dist/dsl/monitor/create-monitor.js +8 -5
  87. package/dist/dsl/monitor/create-monitor.js.map +1 -1
  88. package/dist/dsl/monitor/process-one-position.d.ts +4 -0
  89. package/dist/dsl/monitor/process-one-position.d.ts.map +1 -1
  90. package/dist/dsl/monitor/process-one-position.js +8 -2
  91. package/dist/dsl/monitor/process-one-position.js.map +1 -1
  92. package/dist/dsl/plugin/index.d.ts.map +1 -1
  93. package/dist/dsl/plugin/index.js +3 -1
  94. package/dist/dsl/plugin/index.js.map +1 -1
  95. package/dist/health/index.d.ts +5 -2
  96. package/dist/health/index.d.ts.map +1 -1
  97. package/dist/health/index.js +106 -6
  98. package/dist/health/index.js.map +1 -1
  99. package/dist/health/types.d.ts +102 -0
  100. package/dist/health/types.d.ts.map +1 -1
  101. package/dist/health/types.js +7 -1
  102. package/dist/health/types.js.map +1 -1
  103. package/dist/index.d.ts +2 -2
  104. package/dist/index.d.ts.map +1 -1
  105. package/dist/index.js +98 -1
  106. package/dist/index.js.map +1 -1
  107. package/dist/risk/guardrail.types.d.ts +53 -0
  108. package/dist/risk/guardrail.types.d.ts.map +1 -0
  109. package/dist/risk/guardrail.types.js +5 -0
  110. package/dist/risk/guardrail.types.js.map +1 -0
  111. package/dist/risk/index.d.ts +2 -4
  112. package/dist/risk/index.d.ts.map +1 -1
  113. package/dist/risk/index.js +2 -6
  114. package/dist/risk/index.js.map +1 -1
  115. package/dist/risk/risk-audit-log.d.ts +25 -0
  116. package/dist/risk/risk-audit-log.d.ts.map +1 -0
  117. package/dist/risk/risk-audit-log.js +30 -0
  118. package/dist/risk/risk-audit-log.js.map +1 -0
  119. package/dist/runtime/__tests__/helpers/runtime-gateway-harness.d.ts +162 -0
  120. package/dist/runtime/__tests__/helpers/runtime-gateway-harness.d.ts.map +1 -0
  121. package/dist/runtime/__tests__/helpers/runtime-gateway-harness.js +285 -0
  122. package/dist/runtime/__tests__/helpers/runtime-gateway-harness.js.map +1 -0
  123. package/dist/runtime/create-actions.d.ts +6 -2
  124. package/dist/runtime/create-actions.d.ts.map +1 -1
  125. package/dist/runtime/create-actions.js +18 -7
  126. package/dist/runtime/create-actions.js.map +1 -1
  127. package/dist/runtime/create-scanner-module.d.ts +5 -0
  128. package/dist/runtime/create-scanner-module.d.ts.map +1 -1
  129. package/dist/runtime/create-scanner-module.js +12 -1
  130. package/dist/runtime/create-scanner-module.js.map +1 -1
  131. package/dist/runtime/load-runtime-config.d.ts +1 -1
  132. package/dist/runtime/load-runtime-config.d.ts.map +1 -1
  133. package/dist/runtime/load-runtime-config.js +37 -1
  134. package/dist/runtime/load-runtime-config.js.map +1 -1
  135. package/dist/runtime/map-strategies.d.ts +1 -1
  136. package/dist/runtime/map-strategies.d.ts.map +1 -1
  137. package/dist/runtime/map-strategies.js +38 -1
  138. package/dist/runtime/map-strategies.js.map +1 -1
  139. package/dist/runtime/risk-guard.d.ts +23 -2
  140. package/dist/runtime/risk-guard.d.ts.map +1 -1
  141. package/dist/runtime/risk-guard.js +441 -5
  142. package/dist/runtime/risk-guard.js.map +1 -1
  143. package/dist/runtime/run.d.ts +7 -0
  144. package/dist/runtime/run.d.ts.map +1 -1
  145. package/dist/runtime/run.js +3 -0
  146. package/dist/runtime/run.js.map +1 -1
  147. package/dist/runtime/runtime-schema.d.ts +1169 -24
  148. package/dist/runtime/runtime-schema.d.ts.map +1 -1
  149. package/dist/runtime/runtime-schema.js +105 -2
  150. package/dist/runtime/runtime-schema.js.map +1 -1
  151. package/dist/runtime/runtime.d.ts +26 -0
  152. package/dist/runtime/runtime.d.ts.map +1 -1
  153. package/dist/runtime/runtime.js +192 -6
  154. package/dist/runtime/runtime.js.map +1 -1
  155. package/dist/runtime/scanner-composition.d.ts +10 -0
  156. package/dist/runtime/scanner-composition.d.ts.map +1 -1
  157. package/dist/runtime/scanner-composition.js +10 -0
  158. package/dist/runtime/scanner-composition.js.map +1 -1
  159. package/dist/runtime/scanner-registry.d.ts +39 -1
  160. package/dist/runtime/scanner-registry.d.ts.map +1 -1
  161. package/dist/runtime/scanner-registry.js +105 -2
  162. package/dist/runtime/scanner-registry.js.map +1 -1
  163. package/dist/runtime/state-layout.d.ts +2 -0
  164. package/dist/runtime/state-layout.d.ts.map +1 -1
  165. package/dist/runtime/state-layout.js +1 -0
  166. package/dist/runtime/state-layout.js.map +1 -1
  167. package/dist/runtime/validate-action-prompts.d.ts +30 -0
  168. package/dist/runtime/validate-action-prompts.d.ts.map +1 -0
  169. package/dist/runtime/validate-action-prompts.js +110 -0
  170. package/dist/runtime/validate-action-prompts.js.map +1 -0
  171. package/dist/scanners/__tests__/test-helpers.d.ts +10 -0
  172. package/dist/scanners/__tests__/test-helpers.d.ts.map +1 -1
  173. package/dist/scanners/__tests__/test-helpers.js +52 -0
  174. package/dist/scanners/__tests__/test-helpers.js.map +1 -1
  175. package/dist/scanners/engine/engine.d.ts +37 -0
  176. package/dist/scanners/engine/engine.d.ts.map +1 -1
  177. package/dist/scanners/engine/engine.js +132 -14
  178. package/dist/scanners/engine/engine.js.map +1 -1
  179. package/dist/scanners/engine/result-builder.d.ts +16 -0
  180. package/dist/scanners/engine/result-builder.d.ts.map +1 -1
  181. package/dist/scanners/engine/result-builder.js +22 -0
  182. package/dist/scanners/engine/result-builder.js.map +1 -1
  183. package/dist/scanners/engine/strategy-registry.d.ts +2 -0
  184. package/dist/scanners/engine/strategy-registry.d.ts.map +1 -1
  185. package/dist/scanners/engine/strategy-registry.js +5 -1
  186. package/dist/scanners/engine/strategy-registry.js.map +1 -1
  187. package/dist/scanners/external-scanner-receiver.d.ts +118 -0
  188. package/dist/scanners/external-scanner-receiver.d.ts.map +1 -0
  189. package/dist/scanners/external-scanner-receiver.js +266 -0
  190. package/dist/scanners/external-scanner-receiver.js.map +1 -0
  191. package/dist/scanners/implementations/external-scanner.d.ts +17 -0
  192. package/dist/scanners/implementations/external-scanner.d.ts.map +1 -0
  193. package/dist/scanners/implementations/external-scanner.js +51 -0
  194. package/dist/scanners/implementations/external-scanner.js.map +1 -0
  195. package/dist/scanners/implementations/index.d.ts +1 -0
  196. package/dist/scanners/implementations/index.d.ts.map +1 -1
  197. package/dist/scanners/implementations/index.js +1 -0
  198. package/dist/scanners/implementations/index.js.map +1 -1
  199. package/dist/scanners/implementations/position-tracker.d.ts.map +1 -1
  200. package/dist/scanners/implementations/position-tracker.js +3 -1
  201. package/dist/scanners/implementations/position-tracker.js.map +1 -1
  202. package/dist/scanners/index.d.ts +4 -1
  203. package/dist/scanners/index.d.ts.map +1 -1
  204. package/dist/scanners/index.js +2 -0
  205. package/dist/scanners/index.js.map +1 -1
  206. package/dist/scanners/protocol/scanner.d.ts +3 -1
  207. package/dist/scanners/protocol/scanner.d.ts.map +1 -1
  208. package/dist/scanners/providers/client.d.ts.map +1 -1
  209. package/dist/scanners/providers/client.js +0 -8
  210. package/dist/scanners/providers/client.js.map +1 -1
  211. package/dist/scanners/runtime-module.d.ts +10 -0
  212. package/dist/scanners/runtime-module.d.ts.map +1 -1
  213. package/dist/scanners/runtime-module.js +19 -3
  214. package/dist/scanners/runtime-module.js.map +1 -1
  215. package/dist/scanners/scanner-definition.d.ts +12 -1
  216. package/dist/scanners/scanner-definition.d.ts.map +1 -1
  217. package/dist/scanners/types.d.ts +3 -0
  218. package/dist/scanners/types.d.ts.map +1 -1
  219. package/dist/scanners/types.js.map +1 -1
  220. package/dist/scripts/run-dsl-standalone-live.js +1 -1
  221. package/dist/scripts/run-dsl-standalone-live.js.map +1 -1
  222. package/dist/scripts/run-dsl-standalone-mock.js +1 -1
  223. package/dist/scripts/run-dsl-standalone-mock.js.map +1 -1
  224. package/dist/senpi/client.d.ts +27 -2
  225. package/dist/senpi/client.d.ts.map +1 -1
  226. package/dist/senpi/client.js +74 -1
  227. package/dist/senpi/client.js.map +1 -1
  228. package/dist/senpi/index.d.ts +1 -1
  229. package/dist/senpi/index.d.ts.map +1 -1
  230. package/dist/senpi/types.d.ts +68 -0
  231. package/dist/senpi/types.d.ts.map +1 -1
  232. package/dist/strategy/strategy-state.d.ts +4 -1
  233. package/dist/strategy/strategy-state.d.ts.map +1 -1
  234. package/dist/strategy/strategy-state.js +7 -2
  235. package/dist/strategy/strategy-state.js.map +1 -1
  236. package/dist/tracking/constants.d.ts +24 -0
  237. package/dist/tracking/constants.d.ts.map +1 -0
  238. package/dist/tracking/constants.js +46 -0
  239. package/dist/tracking/constants.js.map +1 -0
  240. package/dist/tracking/index.d.ts +12 -0
  241. package/dist/tracking/index.d.ts.map +1 -0
  242. package/dist/tracking/index.js +8 -0
  243. package/dist/tracking/index.js.map +1 -0
  244. package/dist/tracking/tracker.d.ts +22 -0
  245. package/dist/tracking/tracker.d.ts.map +1 -0
  246. package/dist/tracking/tracker.js +44 -0
  247. package/dist/tracking/tracker.js.map +1 -0
  248. package/dist/tracking/tracking-handler.d.ts +12 -0
  249. package/dist/tracking/tracking-handler.d.ts.map +1 -0
  250. package/dist/tracking/tracking-handler.js +148 -0
  251. package/dist/tracking/tracking-handler.js.map +1 -0
  252. package/dist/tracking/transport.d.ts +35 -0
  253. package/dist/tracking/transport.d.ts.map +1 -0
  254. package/dist/tracking/transport.js +117 -0
  255. package/dist/tracking/transport.js.map +1 -0
  256. package/dist/tracking/types.d.ts +21 -0
  257. package/dist/tracking/types.d.ts.map +1 -0
  258. package/dist/tracking/types.js +6 -0
  259. package/dist/tracking/types.js.map +1 -0
  260. package/dist/types/action.d.ts +13 -2
  261. package/dist/types/action.d.ts.map +1 -1
  262. package/dist/types/dsl/index.d.ts +3 -0
  263. package/dist/types/dsl/index.d.ts.map +1 -1
  264. package/dist/types/strategy.d.ts +9 -3
  265. package/dist/types/strategy.d.ts.map +1 -1
  266. package/dist/utils/logger.d.ts +1 -0
  267. package/dist/utils/logger.d.ts.map +1 -1
  268. package/dist/utils/logger.js +19 -1
  269. package/dist/utils/logger.js.map +1 -1
  270. package/dist/utils/resolve-order-type.d.ts +5 -0
  271. package/dist/utils/resolve-order-type.d.ts.map +1 -0
  272. package/dist/utils/resolve-order-type.js +29 -0
  273. package/dist/utils/resolve-order-type.js.map +1 -0
  274. package/examples/strategies/dsl-showcase.yaml +7 -2
  275. package/examples/strategies/dsl.yaml +5 -1
  276. package/examples/strategies/fox-minimal-loosened.yaml +18 -3
  277. package/examples/strategies/fox-minimal.yaml +25 -3
  278. package/examples/strategies/minimal.yaml +4 -2
  279. package/examples/strategies/momentum/how-it-works.md +47 -0
  280. package/examples/strategies/momentum/momentum-guarded.yaml +161 -0
  281. package/examples/strategies/risk-showcase.yaml +93 -0
  282. package/examples/strategies/viper.yaml +11 -3
  283. package/examples/strategies/wolf.yaml +11 -3
  284. package/examples/yamls/sample-with-dsl-and-emerging-movers.yaml +12 -4
  285. package/package.json +4 -4
@@ -7,12 +7,30 @@ const levelOrder = {
7
7
  warn: 2,
8
8
  error: 3,
9
9
  };
10
- let minLevel = "info";
10
+ const DEFAULT_LEVEL = "info";
11
+ function resolveInitialLevel() {
12
+ const raw = process.env.SENPI_LOG_LEVEL;
13
+ if (raw == null || raw === "")
14
+ return DEFAULT_LEVEL;
15
+ const normalized = raw.toLowerCase();
16
+ if (normalized === "debug" ||
17
+ normalized === "info" ||
18
+ normalized === "warn" ||
19
+ normalized === "error") {
20
+ return normalized;
21
+ }
22
+ console.warn(`[logger] Unknown SENPI_LOG_LEVEL="${raw}"; falling back to "${DEFAULT_LEVEL}"`);
23
+ return DEFAULT_LEVEL;
24
+ }
25
+ let minLevel = resolveInitialLevel();
11
26
  let errorNotifier = null;
12
27
  let notifyingError = false;
13
28
  export function setLogLevel(level) {
14
29
  minLevel = level;
15
30
  }
31
+ export function getLogLevel() {
32
+ return minLevel;
33
+ }
16
34
  export function setErrorNotifier(notifier) {
17
35
  errorNotifier = notifier;
18
36
  }
@@ -1 +1 @@
1
- {"version":3,"file":"logger.js","sourceRoot":"","sources":["../../src/utils/logger.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"logger.js","sourceRoot":"","sources":["../../src/utils/logger.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ import type { OrderType, CloseOrderType, FeeOptimizedLimitOptions } from '../senpi/types.js';
2
+ export declare function resolveOpenOrderType(raw: unknown): OrderType;
3
+ export declare function resolveCloseOrderType(raw: unknown): CloseOrderType;
4
+ export declare function resolveFeeOptimizedLimitOptions(raw: unknown): FeeOptimizedLimitOptions | undefined;
5
+ //# sourceMappingURL=resolve-order-type.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resolve-order-type.d.ts","sourceRoot":"","sources":["../../src/utils/resolve-order-type.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,cAAc,EAAE,wBAAwB,EAAE,MAAM,mBAAmB,CAAC;AAM7F,wBAAgB,oBAAoB,CAAC,GAAG,EAAE,OAAO,GAAG,SAAS,CAI5D;AAED,wBAAgB,qBAAqB,CAAC,GAAG,EAAE,OAAO,GAAG,cAAc,CAIlE;AAED,wBAAgB,+BAA+B,CAAC,GAAG,EAAE,OAAO,GAAG,wBAAwB,GAAG,SAAS,CAOlG"}
@@ -0,0 +1,29 @@
1
+ import { createLogger } from './logger.js';
2
+ import { VALID_OPEN_ORDER_TYPES, VALID_CLOSE_ORDER_TYPES } from '../constants/order-types.js';
3
+ const logger = createLogger('[order-type]');
4
+ export function resolveOpenOrderType(raw) {
5
+ if (typeof raw === 'string' && VALID_OPEN_ORDER_TYPES.has(raw))
6
+ return raw;
7
+ if (raw != null)
8
+ logger.warn('invalid order_type for open, falling back to MARKET', { value: raw });
9
+ return 'MARKET';
10
+ }
11
+ export function resolveCloseOrderType(raw) {
12
+ if (typeof raw === 'string' && VALID_CLOSE_ORDER_TYPES.has(raw))
13
+ return raw;
14
+ if (raw != null)
15
+ logger.warn('invalid order_type for close, falling back to MARKET', { value: raw });
16
+ return 'MARKET';
17
+ }
18
+ export function resolveFeeOptimizedLimitOptions(raw) {
19
+ if (raw == null || typeof raw !== 'object' || Array.isArray(raw))
20
+ return undefined;
21
+ const obj = raw;
22
+ const result = {};
23
+ if (typeof obj.ensure_execution_as_taker === 'boolean')
24
+ result.ensureExecutionAsTaker = obj.ensure_execution_as_taker;
25
+ if (typeof obj.execution_timeout_seconds === 'number')
26
+ result.executionTimeoutSeconds = obj.execution_timeout_seconds;
27
+ return Object.keys(result).length > 0 ? result : undefined;
28
+ }
29
+ //# sourceMappingURL=resolve-order-type.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resolve-order-type.js","sourceRoot":"","sources":["../../src/utils/resolve-order-type.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC3C,OAAO,EAAE,sBAAsB,EAAE,uBAAuB,EAAE,MAAM,6BAA6B,CAAC;AAE9F,MAAM,MAAM,GAAG,YAAY,CAAC,cAAc,CAAC,CAAC;AAE5C,MAAM,UAAU,oBAAoB,CAAC,GAAY;IAC/C,IAAI,OAAO,GAAG,KAAK,QAAQ,IAAI,sBAAsB,CAAC,GAAG,CAAC,GAAgB,CAAC;QAAE,OAAO,GAAgB,CAAC;IACrG,IAAI,GAAG,IAAI,IAAI;QAAE,MAAM,CAAC,IAAI,CAAC,qDAAqD,EAAE,EAAE,KAAK,EAAE,GAAG,EAAE,CAAC,CAAC;IACpG,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED,MAAM,UAAU,qBAAqB,CAAC,GAAY;IAChD,IAAI,OAAO,GAAG,KAAK,QAAQ,IAAI,uBAAuB,CAAC,GAAG,CAAC,GAAqB,CAAC;QAAE,OAAO,GAAqB,CAAC;IAChH,IAAI,GAAG,IAAI,IAAI;QAAE,MAAM,CAAC,IAAI,CAAC,sDAAsD,EAAE,EAAE,KAAK,EAAE,GAAG,EAAE,CAAC,CAAC;IACrG,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED,MAAM,UAAU,+BAA+B,CAAC,GAAY;IAC1D,IAAI,GAAG,IAAI,IAAI,IAAI,OAAO,GAAG,KAAK,QAAQ,IAAI,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC;QAAE,OAAO,SAAS,CAAC;IACnF,MAAM,GAAG,GAAG,GAA8B,CAAC;IAC3C,MAAM,MAAM,GAA6B,EAAE,CAAC;IAC5C,IAAI,OAAO,GAAG,CAAC,yBAAyB,KAAK,SAAS;QAAE,MAAM,CAAC,sBAAsB,GAAG,GAAG,CAAC,yBAAyB,CAAC;IACtH,IAAI,OAAO,GAAG,CAAC,yBAAyB,KAAK,QAAQ;QAAE,MAAM,CAAC,uBAAuB,GAAG,GAAG,CAAC,yBAAyB,CAAC;IACtH,OAAO,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,SAAS,CAAC;AAC7D,CAAC"}
@@ -14,9 +14,8 @@ notifications:
14
14
 
15
15
  strategy:
16
16
  wallet: "${WALLET_ADDRESS}"
17
- budget: 500
18
17
  slots: 2
19
- margin_per_slot: 200
18
+ margin_pct: 15
20
19
  trading_risk: conservative
21
20
  enabled: true
22
21
 
@@ -37,6 +36,12 @@ exit:
37
36
  engine: dsl
38
37
  # interval_seconds — how often the price monitor runs
39
38
  interval_seconds: 30
39
+ # order_type — execution method for DSL exit closes: MARKET (default) or FEE_OPTIMIZED_LIMIT
40
+ order_type: FEE_OPTIMIZED_LIMIT
41
+ # fee_optimized_limit_options — only used when order_type is FEE_OPTIMIZED_LIMIT
42
+ fee_optimized_limit_options:
43
+ ensure_execution_as_taker: true # fall back to market if maker doesn't fill
44
+ execution_timeout_seconds: 15 # seconds to wait for maker fill (default 45)
40
45
  # dsl_preset — single exit profile (required for DslPlugin).
41
46
  dsl_preset:
42
47
  hard_timeout:
@@ -6,7 +6,7 @@ description: >
6
6
  into the DSL exit engine for automated trailing stop-loss management.
7
7
 
8
8
  # ── STRATEGY ──
9
- # Minimal: only wallet address + optional fields (no budget/slots/margin needed)
9
+ # Minimal: only wallet address + optional fields (no slots/margin needed for watch-only)
10
10
  strategy:
11
11
  wallet: "${WALLET_ADDRESS}"
12
12
  enabled: true
@@ -28,6 +28,10 @@ actions:
28
28
  exit:
29
29
  engine: dsl
30
30
  interval_seconds: 30
31
+ order_type: FEE_OPTIMIZED_LIMIT
32
+ fee_optimized_limit_options:
33
+ ensure_execution_as_taker: true
34
+ execution_timeout_seconds: 15
31
35
  dsl_preset:
32
36
  phase1:
33
37
  enabled: true
@@ -10,9 +10,8 @@ notifications:
10
10
 
11
11
  strategy:
12
12
  wallet: "${FOX_WALLET}"
13
- budget: "100"
14
13
  slots: 3
15
- margin_per_slot: 30
14
+ margin_pct: 10
16
15
  trading_risk: aggressive
17
16
  enabled: true
18
17
 
@@ -111,6 +110,11 @@ actions:
111
110
  decision_model: ${DECISION_MODEL}
112
111
  scanners: [emerging_movers]
113
112
  min_confidence: 4
113
+ params:
114
+ order_type: FEE_OPTIMIZED_LIMIT
115
+ fee_optimized_limit_options:
116
+ ensure_execution_as_taker: true
117
+ execution_timeout_seconds: 15
114
118
  context:
115
119
  - type: signal
116
120
  scanner: emerging_movers
@@ -177,7 +181,7 @@ actions:
177
181
  "reasoning": "one sentence",
178
182
  "payload": {
179
183
  "signals": [
180
- { "asset": "<ticker>", "direction": "LONG" or "SHORT", "reason": "one sentence", "rotate_out": "<asset_to_cut>" }
184
+ { "asset": "<ticker>", "direction": "LONG" or "SHORT", "reason": "one sentence", "rotate_out": "<asset_to_cut>", "leverage": "<optional number>", "margin": "<optional $ amount>" }
181
185
  ]
182
186
  }
183
187
  }
@@ -188,6 +192,11 @@ actions:
188
192
  decision_mode: rule
189
193
  scanners: [sm_flip]
190
194
  min_confidence: 1
195
+ params:
196
+ order_type: FEE_OPTIMIZED_LIMIT
197
+ fee_optimized_limit_options:
198
+ ensure_execution_as_taker: true
199
+ execution_timeout_seconds: 10
191
200
 
192
201
  # ── Watchdog: emergency close on margin danger ──
193
202
  - name: watchdog_close
@@ -195,11 +204,17 @@ actions:
195
204
  decision_mode: rule
196
205
  scanners: [watchdog]
197
206
  min_confidence: 1
207
+ params:
208
+ order_type: MARKET
198
209
 
199
210
  # ── DSL — trailing exit
200
211
  exit:
201
212
  engine: dsl
202
213
  interval_seconds: 30
214
+ order_type: FEE_OPTIMIZED_LIMIT
215
+ fee_optimized_limit_options:
216
+ ensure_execution_as_taker: true
217
+ execution_timeout_seconds: 15
203
218
  dsl_preset:
204
219
  hard_timeout:
205
220
  enabled: false
@@ -8,7 +8,6 @@ description: >
8
8
 
9
9
  strategy:
10
10
  wallet: "${FOX_WALLET}"
11
- budget: "500"
12
11
  slots: 1
13
12
  margin_per_slot: 100
14
13
  trading_risk: aggressive
@@ -109,6 +108,11 @@ actions:
109
108
  decision_model: claude-sonnet-4-6
110
109
  scanners: [emerging_movers]
111
110
  min_confidence: 7
111
+ params:
112
+ order_type: FEE_OPTIMIZED_LIMIT
113
+ fee_optimized_limit_options:
114
+ ensure_execution_as_taker: true
115
+ execution_timeout_seconds: 15
112
116
  context:
113
117
  - type: signal
114
118
  scanner: emerging_movers
@@ -182,7 +186,14 @@ actions:
182
186
  "reasoning": "one sentence",
183
187
  "payload": {
184
188
  "signals": [
185
- { "asset": "<ticker>", "direction": "LONG" or "SHORT", "reason": "one sentence", "rotate_out": "<asset_to_cut>" }
189
+ {
190
+ "asset": "<ticker>",
191
+ "direction": "LONG" or "SHORT",
192
+ "reason": "one sentence",
193
+ "rotate_out": "<asset_to_cut>",
194
+ "leverage": <number, optional — your recommended leverage>,
195
+ "margin": <number, optional — $ margin amount>
196
+ }
186
197
  ]
187
198
  }
188
199
  }
@@ -193,6 +204,11 @@ actions:
193
204
  decision_mode: rule
194
205
  scanners: [sm_flip]
195
206
  min_confidence: 1
207
+ params:
208
+ order_type: FEE_OPTIMIZED_LIMIT
209
+ fee_optimized_limit_options:
210
+ ensure_execution_as_taker: true
211
+ execution_timeout_seconds: 10
196
212
 
197
213
  # ── Watchdog: emergency close on margin danger ──
198
214
  - name: watchdog_close
@@ -200,11 +216,17 @@ actions:
200
216
  decision_mode: rule
201
217
  scanners: [watchdog]
202
218
  min_confidence: 1
219
+ params:
220
+ order_type: MARKET
203
221
 
204
- # ── DSL — trailing exit
222
+ # ── DSL — trailing exit
205
223
  exit:
206
224
  engine: dsl
207
225
  interval_seconds: 30
226
+ order_type: FEE_OPTIMIZED_LIMIT
227
+ fee_optimized_limit_options:
228
+ ensure_execution_as_taker: true
229
+ execution_timeout_seconds: 15
208
230
  dsl_preset:
209
231
  phase1:
210
232
  enabled: true
@@ -4,9 +4,7 @@ description: Watch-only strategy — logs signals, opens no positions.
4
4
 
5
5
  strategy:
6
6
  wallet: "${WALLET_ADDRESS}"
7
- budget: "0"
8
7
  slots: 1
9
- margin_per_slot: 0
10
8
  trading_risk: conservative
11
9
  enabled: true
12
10
 
@@ -29,6 +27,10 @@ actions:
29
27
  exit:
30
28
  engine: dsl
31
29
  interval_seconds: 60
30
+ order_type: FEE_OPTIMIZED_LIMIT
31
+ fee_optimized_limit_options:
32
+ ensure_execution_as_taker: true
33
+ execution_timeout_seconds: 30
32
34
  dsl_preset:
33
35
  phase1:
34
36
  enabled: true
@@ -0,0 +1,47 @@
1
+ # `momentum-guarded` — How it works
2
+
3
+ Companion notes for [`examples/strategies/momentum-guarded.yaml`](../momentum-guarded.yaml).
4
+
5
+ ## The trading thesis
6
+
7
+ Catch **short-horizon directional breakouts** on liquid Hyperliquid perps the moment a 1h candle prints an outsized move vs. the prior close — but only when the move passes both an LLM sanity check and a real-time risk gauntlet, and only with a trailing-exit playbook strict enough to survive momentum reversals.
8
+
9
+ ## Signal flow (entry side)
10
+
11
+ 1. **External producer** ([`src/scanners/external/momentum/producer.mjs`](../../../src/scanners/external/momentum/producer.mjs)) runs out-of-process — pulls instruments + 1h candles from Senpi MCP, computes last-vs-prev close % move, and ingests `MOMENTUM_BREAKOUT` signals via `senpi.ingestExternalScannerData`. Re-run on a cron / `watch`.
12
+ 2. The runtime's `external_momentum` scanner of type `external_scanner` accepts the push, validates the payload schema (`sourceMeta`, `sourceFactors`, …), and emits a `scanner:run:complete` event carrying the signals.
13
+ 3. `momentum_entry` (an `OPEN_POSITION` action with `decision_mode: llm`) consumes the signals, runs each through a 6-step gauntlet (move magnitude ≥1.5%, direction matches sign, day notional ≥1M, max leverage ≥5, producer score ≥0.4, pick highest-score), and returns at most one trade. `min_confidence: 7` blocks lukewarm LLM verdicts.
14
+ 4. **Risk gates** fire before the position opens. With `slots: 3` and `margin_per_slot: 300` (~$900 deployed of a $5k budget), the gauntlet of guardrails is:
15
+ - `daily_loss_limit_pct: 4` — closes the gate if today's PnL drops 4% of day-open account value.
16
+ - `drawdown_halt_pct: 20` — closes the gate at 20% PnL drawdown from peak (peak carries ~24h, not reset at midnight).
17
+ - `max_entries_per_day: 6` — caps churn on noisy breakout days.
18
+ - `max_consecutive_losses: 3` + `cooldown_minutes: 90` — three losers in a row pauses entries for 90 min so the strategy doesn't tilt.
19
+ - `per_asset_cooldown_minutes: 45` — no re-entry on the same ticker for 45 min after a close (avoids whipsaw fills).
20
+
21
+ Order matters: **CLOSED beats COOLDOWN beats OPEN**; the first non-OPEN gate short-circuits.
22
+ 5. If everything passes, `FEE_OPTIMIZED_LIMIT` posts the order with a 15s execution timeout (taker fallback guaranteed).
23
+
24
+ ## Position management (exit side)
25
+
26
+ Once filled, the **DSL exit engine** owns the position (`position_tracker` keeps it in sync even for manually-opened positions on the same wallet):
27
+
28
+ - **Phase 1** — fixed stop at `-2.5%` plus a `7%` retrace floor; needs `3` consecutive breaches before firing (debounce against single-tick spikes).
29
+ - **Phase 2** — once price advances, trailing floors lock in profit on a four-tier ladder:
30
+ - +6% → lock 35% of high-water
31
+ - +10% → lock 55%
32
+ - +15% → lock 70%
33
+ - +20% → lock 85%
34
+ - **Time-based cuts** — momentum that fails to develop is the silent killer:
35
+ - `dead_weight_cut` after 30 min flat → close.
36
+ - `weak_peak_cut` after 45 min if peak < +2% → close.
37
+ - `hard_timeout` at 2 hours → close regardless.
38
+
39
+ ## What this looks like in practice
40
+
41
+ - A trader runs the producer every minute via cron.
42
+ - 90% of producer ticks emit zero signals; the runtime stays idle.
43
+ - When BTC prints a +2% 1h candle on healthy volume, the LLM accepts, the risk gauntlet checks daily PnL/drawdown/entries/cooldowns, and one slot fires a long.
44
+ - DSL trails the move. If BTC stalls, time-cuts close it within ~30–45 min instead of bleeding margin. If BTC runs to +12%, the +10% tier locks in 55% of the high-water, so a retrace to +5% still books profit.
45
+ - A bad day (3 stop-outs) trips the consecutive-loss cooldown — the runtime stops trying for 90 min and resumes fresh.
46
+
47
+ Net effect: **a small, slot-bounded, risk-gated breakout sniper** with strict trailing protection — appropriate for a $5k moderate-risk wallet that wants asymmetric upside without unsupervised drawdown.
@@ -0,0 +1,161 @@
1
+ name: momentum-guarded
2
+ version: 1.0.0
3
+ description: >
4
+ Risk-managed external momentum strategy. An out-of-process producer
5
+ (src/scanners/external/momentum/producer.mjs) pushes MOMENTUM_BREAKOUT
6
+ signals into the runtime; an LLM gauntlet decides which breakouts deserve
7
+ capital; the risk component gates every entry against daily loss, drawdown,
8
+ per-day entry count, consecutive-loss cooldown, and per-asset cooldown;
9
+ the DSL exit engine manages trailing exits on accepted fills.
10
+
11
+ notifications:
12
+ telegram_chat_id: "${TELEGRAM_CHAT_ID}"
13
+
14
+ strategy:
15
+ wallet: "${WALLET_ADDRESS}"
16
+ budget: 5000
17
+ slots: 3
18
+ margin_per_slot: 300
19
+ trading_risk: moderate
20
+ enabled: true
21
+
22
+ # ── RISK ──
23
+ # Real-time gates enforced on every OPEN_POSITION attempt. Any non-OPEN gate
24
+ # short-circuits and skips the entry. See docs/risk-component.md.
25
+ risk:
26
+ data_retention_hours: 72
27
+
28
+ guard_rails:
29
+ # Daily loss halt — stop trading if daily PnL drops > 4% of day-open account value.
30
+ daily_loss_limit_pct: 4
31
+
32
+ # Cap entries per UTC day so a noisy producer day can't churn the wallet.
33
+ max_entries_per_day: 6
34
+ bypass_max_entries_per_day_on_profit: false
35
+
36
+ # Consecutive-loss cooldown — three losers in a row pauses entries for 90 min.
37
+ max_consecutive_losses: 3
38
+ cooldown_minutes: 90
39
+
40
+ # Drawdown halt — 20% PnL drawdown from peak halts entries; peak carries ~24h.
41
+ drawdown_halt_pct: 20
42
+ drawdown_reset_on_day_rollover: false
43
+
44
+ # Per-asset cooldown — no re-entry on the same asset for 45 min after a close.
45
+ per_asset_cooldown_minutes: 45
46
+
47
+ # ── SCANNERS ──
48
+ scanners:
49
+ # Onchain position tracker — emits position lifecycle events into the DSL exit engine.
50
+ - name: position_tracker
51
+ type: position_tracker
52
+ interval: 10s
53
+
54
+ # External producer feed — schema for inbound MOMENTUM_BREAKOUT signals
55
+ # delivered via senpi.ingestExternalScannerData.
56
+ - name: external_momentum
57
+ type: external_scanner
58
+ outputs:
59
+ signals: true
60
+ context: false
61
+ config:
62
+ fields:
63
+ sourceScannerId: { type: string, required: true }
64
+ sourceSignalType: { type: string, required: true }
65
+ sourceTimestamp: { type: number, required: true }
66
+ sourceFactors: { type: object, required: true }
67
+ sourceMeta: { type: object, required: true }
68
+
69
+ # ── ACTIONS ──
70
+ actions:
71
+ # Position lifecycle tracking — feeds the DSL exit engine.
72
+ - name: position_tracker_action
73
+ action_type: POSITION_TRACKER
74
+ decision_mode: rule
75
+ scanners: [position_tracker]
76
+
77
+ # Entry: LLM gauntlet on momentum breakout signals.
78
+ - name: momentum_entry
79
+ action_type: OPEN_POSITION
80
+ decision_mode: llm
81
+ decision_model: claude-sonnet-4-20250514
82
+ scanners: [external_momentum]
83
+ min_confidence: 7
84
+ params:
85
+ order_type: FEE_OPTIMIZED_LIMIT
86
+ fee_optimized_limit_options:
87
+ ensure_execution_as_taker: true
88
+ execution_timeout_seconds: 15
89
+ context:
90
+ - type: signal
91
+ scanner: external_momentum
92
+ decision_prompt: |
93
+ You are a trade-decisioning evaluator. Given a MOMENTUM_BREAKOUT
94
+ signal pushed by the external momentum producer, decide whether to
95
+ open a position on it or skip.
96
+
97
+ A MOMENTUM_BREAKOUT fires when an asset's latest closed candle moves
98
+ by at least the producer's threshold vs. the previous close on the
99
+ signal's timeframe — i.e. a short-term directional breakout in price.
100
+ `meta.movePct` carries the signed % change (positive = LONG bias,
101
+ negative = SHORT bias); `score` (0..1) scales with the move's
102
+ magnitude; `meta.dayNtlVlm` and `meta.maxLeverage` describe the
103
+ instrument's liquidity and leverage headroom.
104
+
105
+ SIGNAL DATA:
106
+ {{signal_external_momentum}}
107
+
108
+ ═══ GAUNTLET ═══
109
+ 1. movePct magnitude — require |movePct| >= 1.5; reject sub-threshold noise.
110
+ 2. Direction sanity — LONG only if movePct > 0, SHORT only if movePct < 0.
111
+ 3. Liquidity — meta.dayNtlVlm must be >= 1_000_000.
112
+ 4. Leverage — meta.maxLeverage must be >= 5; skip otherwise.
113
+ 5. Score — use the producer score (0..1) as a proxy for strength; require >= 0.4.
114
+ 6. One signal at a time — pick the highest-score eligible signal; skip the rest.
115
+
116
+ Respond with a single JSON object:
117
+ {
118
+ "execute": true|false,
119
+ "actionType": "OPEN_POSITION",
120
+ "confidence": 1-10,
121
+ "reasoning": "one sentence",
122
+ "payload": {
123
+ "signals": [
124
+ { "asset": "<ticker>", "direction": "LONG"|"SHORT", "reason": "one sentence" }
125
+ ]
126
+ }
127
+ }
128
+
129
+ # ── EXIT (DSL) ──
130
+ # Trailing stop-loss tuned for short-horizon momentum entries.
131
+ # Time-based cuts catch stalled trades that never deliver follow-through.
132
+ exit:
133
+ engine: dsl
134
+ interval_seconds: 30
135
+ order_type: FEE_OPTIMIZED_LIMIT
136
+ fee_optimized_limit_options:
137
+ ensure_execution_as_taker: true
138
+ execution_timeout_seconds: 15
139
+ dsl_preset:
140
+ hard_timeout:
141
+ enabled: true
142
+ interval_in_minutes: 120
143
+ weak_peak_cut:
144
+ enabled: true
145
+ interval_in_minutes: 45
146
+ min_value: 2
147
+ dead_weight_cut:
148
+ enabled: true
149
+ interval_in_minutes: 30
150
+ phase1:
151
+ enabled: true
152
+ max_loss_pct: 2.5
153
+ retrace_threshold: 7
154
+ consecutive_breaches_required: 3
155
+ phase2:
156
+ enabled: true
157
+ tiers:
158
+ - { trigger_pct: 6, lock_hw_pct: 35 }
159
+ - { trigger_pct: 10, lock_hw_pct: 55 }
160
+ - { trigger_pct: 15, lock_hw_pct: 70 }
161
+ - { trigger_pct: 20, lock_hw_pct: 85 }
@@ -0,0 +1,93 @@
1
+ # Risk showcase — every risk guardrail field annotated for reference.
2
+ # Use as a copy-paste reference when configuring risk management.
3
+ name: risk-showcase
4
+ version: 1.0.0
5
+ description: >
6
+ Annotated risk guardrails config reference.
7
+ Uses position_tracker scanner with DSL exit engine.
8
+ Lists explicit example values for each field (not implicit runtime defaults).
9
+
10
+ notifications:
11
+ telegram_chat_id: "${TELEGRAM_CHAT_ID}"
12
+
13
+ strategy:
14
+ wallet: "${WALLET_ADDRESS}"
15
+ budget: 10000
16
+ slots: 3
17
+ margin_per_slot: 250
18
+ trading_risk: moderate
19
+ enabled: true
20
+
21
+ # ── RISK ──
22
+ # Optional. Without this block, all gates are OPEN (no risk management).
23
+ risk:
24
+ # How long to keep audit log files (JSONL + daily snapshots), in hours.
25
+ # Range: 1–168 (1 hour to 7 days). Default: 48.
26
+ data_retention_hours: 48
27
+
28
+ guard_rails:
29
+ # ── Daily Loss Halt ──
30
+ # Gate CLOSED when daily trading PnL drop exceeds this % of account value at day open.
31
+ # Uses Hyperliquid portfolio PnL (realized + unrealized + funding, excludes deposits/withdrawals).
32
+ # Resets at UTC midnight.
33
+ daily_loss_limit_pct: 5 # 5% of account value at day open
34
+
35
+ # ── Max Entries Per Day ──
36
+ # Gate CLOSED when position entries today >= max_entries_per_day.
37
+ # Counts open positions opened today (startTime) + closed trades opened today (openTime).
38
+ # Resets at UTC midnight.
39
+ max_entries_per_day: 8
40
+ # When true, max_entries_per_day limit is bypassed if daily realized PnL > 0.
41
+ # Default: false (limit enforced strictly unless explicitly opted in).
42
+ # Not yet evaluated — reserved for future use.
43
+ bypass_max_entries_per_day_on_profit: false
44
+
45
+ # ── Consecutive Loss Cooldown ──
46
+ # Gate COOLDOWN when the last N closed trades all have negative realizedPnl.
47
+ # Stateless: derived from trade history API on every tick, no persisted streak.
48
+ # Streak carries across days. Cooldown window starts from the most recent
49
+ # loss's close time and expires cooldown_minutes later.
50
+ max_consecutive_losses: 3
51
+ cooldown_minutes: 60
52
+
53
+ # ── Drawdown Halt ──
54
+ # Gate CLOSED when PnL drawdown from peak >= drawdown_halt_pct %.
55
+ # PnL-based: immune to deposits and withdrawals.
56
+ # Drawdown = (peak_pnl - current_pnl) / account_value_at_day_open * 100.
57
+ drawdown_halt_pct: 30 # 30% PnL drawdown from peak triggers halt
58
+ # When true, PnL peak resets at UTC midnight (intraday drawdown only).
59
+ # When false (default), PnL peak carries from prior ~24h (perpDay window).
60
+ drawdown_reset_on_day_rollover: false
61
+
62
+ # ── Per-Asset Cooldown ──
63
+ # Gate COOLDOWN for a specific asset when it was closed within the last N minutes.
64
+ # Checked on each entry attempt. Only evaluated when all other gates are OPEN.
65
+ # Minimum: 5 minutes (backend latency floor).
66
+ per_asset_cooldown_minutes: 30 # 30 min cooldown after closing any asset
67
+
68
+ # ── SCANNERS ──
69
+ scanners:
70
+ - name: position_tracker
71
+ type: position_tracker
72
+ interval: 10s
73
+
74
+ # ── ACTIONS ──
75
+ actions:
76
+ - name: position_tracker_action
77
+ action_type: POSITION_TRACKER
78
+ decision_mode: rule
79
+ scanners: [position_tracker]
80
+
81
+ # ── EXIT ──
82
+ exit:
83
+ engine: dsl
84
+ interval_seconds: 30
85
+ dsl_preset:
86
+ phase1:
87
+ max_loss_pct: 5.0
88
+ retrace_threshold: 10
89
+ consecutive_breaches_required: 2
90
+ phase2:
91
+ tiers:
92
+ - { trigger_pct: 10, lock_hw_pct: 50 }
93
+ - { trigger_pct: 20, lock_hw_pct: 70 }
@@ -4,9 +4,8 @@ description: Moderate — candle-based breakouts via prescreener + momentum.
4
4
 
5
5
  strategy:
6
6
  wallet: "${WALLET_ADDRESS}"
7
- budget: 2000
8
7
  slots: 4
9
- margin_per_slot: 400
8
+ margin_pct: 10
10
9
  trading_risk: moderate
11
10
  enabled: true
12
11
 
@@ -37,13 +36,22 @@ actions:
37
36
  decision_model: claude-sonnet-4-20250514
38
37
  scanners: [momentum]
39
38
  min_confidence: 6
39
+ params:
40
+ order_type: FEE_OPTIMIZED_LIMIT
41
+ fee_optimized_limit_options:
42
+ ensure_execution_as_taker: true
43
+ execution_timeout_seconds: 15
40
44
  context: [signal]
41
45
  decision_prompt: |
42
- Evaluate the momentum breakout signal. Reply with JSON: {"execute": true|false, "actionType": "OPEN_POSITION", "confidence": 1-10, "reasoning": "...", "payload": {"signals": [{"asset": "SYMBOL", "direction": "LONG"|"SHORT", "reason": "..."}]}}.
46
+ Evaluate the momentum breakout signal. Reply with JSON: {"execute": true|false, "actionType": "OPEN_POSITION", "confidence": 1-10, "reasoning": "...", "payload": {"signals": [{"asset": "SYMBOL", "direction": "LONG"|"SHORT", "reason": "...", "leverage": <optional number>, "margin": <optional $ amount>}]}}.
43
47
 
44
48
  exit:
45
49
  engine: dsl
46
50
  interval_seconds: 30
51
+ order_type: FEE_OPTIMIZED_LIMIT
52
+ fee_optimized_limit_options:
53
+ ensure_execution_as_taker: true
54
+ execution_timeout_seconds: 15
47
55
  dsl_preset:
48
56
  phase1:
49
57
  enabled: true
@@ -4,9 +4,8 @@ description: Aggressive — early entry on FIRST_JUMP from emerging_movers.
4
4
 
5
5
  strategy:
6
6
  wallet: "${WALLET_ADDRESS}"
7
- budget: 1000
8
7
  slots: 3
9
- margin_per_slot: 300
8
+ margin_pct: 15
10
9
  trading_risk: aggressive
11
10
  enabled: true
12
11
 
@@ -32,13 +31,22 @@ actions:
32
31
  decision_model: claude-sonnet-4-20250514
33
32
  scanners: [emerging_movers]
34
33
  min_confidence: 6
34
+ params:
35
+ order_type: FEE_OPTIMIZED_LIMIT
36
+ fee_optimized_limit_options:
37
+ ensure_execution_as_taker: true
38
+ execution_timeout_seconds: 10
35
39
  context: [signal]
36
40
  decision_prompt: |
37
- Evaluate the signal. Reply with JSON: {"execute": true|false, "actionType": "OPEN_POSITION", "confidence": 1-10, "reasoning": "...", "payload": {"signals": [{"asset": "SYMBOL", "direction": "LONG"|"SHORT", "reason": "..."}]}}.
41
+ Evaluate the signal. Reply with JSON: {"execute": true|false, "actionType": "OPEN_POSITION", "confidence": 1-10, "reasoning": "...", "payload": {"signals": [{"asset": "SYMBOL", "direction": "LONG"|"SHORT", "reason": "...", "leverage": <optional number>, "margin": <optional $ amount>}]}}.
38
42
 
39
43
  exit:
40
44
  engine: dsl
41
45
  interval_seconds: 30
46
+ order_type: FEE_OPTIMIZED_LIMIT
47
+ fee_optimized_limit_options:
48
+ ensure_execution_as_taker: true
49
+ execution_timeout_seconds: 10
42
50
  dsl_preset:
43
51
  hard_timeout:
44
52
  enabled: true