cleanup and refactoring

This commit is contained in:
Miha Kralj
2026-09-23 14:53:01 +02:00
parent 2193c4e6ea
commit 0c9b521df9
45 changed files with 1181 additions and 2928 deletions
+2
View File
@@ -121,3 +121,5 @@ fix-bullets.ps1
fix_bullets.py
fix_read.py
.aider*
sandbox/**
-314
View File
@@ -1,314 +0,0 @@
SSUUMMMMAARRYY OOFF LLEESSSS CCOOMMMMAANNDDSS
Commands marked with * may be preceded by a number, _N.
Notes in parentheses indicate the behavior if _N is given.
A key preceded by a caret indicates the Ctrl key; thus ^K is ctrl-K.
h H Display this help.
q :q Q :Q ZZ Exit.
---------------------------------------------------------------------------
MMOOVVIINNGG
e ^E j ^N CR * Forward one line (or _N lines).
y ^Y k ^K ^P * Backward one line (or _N lines).
f ^F ^V SPACE * Forward one window (or _N lines).
b ^B ESC-v * Backward one window (or _N lines).
z * Forward one window (and set window to _N).
w * Backward one window (and set window to _N).
ESC-SPACE * Forward one window, but don't stop at end-of-file.
d ^D * Forward one half-window (and set half-window to _N).
u ^U * Backward one half-window (and set half-window to _N).
ESC-) RightArrow * Right one half screen width (or _N positions).
ESC-( LeftArrow * Left one half screen width (or _N positions).
ESC-} ^RightArrow Right to last column displayed.
ESC-{ ^LeftArrow Left to first column.
F Forward forever; like "tail -f".
ESC-F Like F but stop when search pattern is found.
r ^R ^L Repaint screen.
R Repaint screen, discarding buffered input.
---------------------------------------------------
Default "window" is the screen height.
Default "half-window" is half of the screen height.
---------------------------------------------------------------------------
SSEEAARRCCHHIINNGG
/_p_a_t_t_e_r_n * Search forward for (_N-th) matching line.
?_p_a_t_t_e_r_n * Search backward for (_N-th) matching line.
n * Repeat previous search (for _N-th occurrence).
N * Repeat previous search in reverse direction.
ESC-n * Repeat previous search, spanning files.
ESC-N * Repeat previous search, reverse dir. & spanning files.
^O^N ^On * Search forward for (_N-th) OSC8 hyperlink.
^O^P ^Op * Search backward for (_N-th) OSC8 hyperlink.
^O^L ^Ol Jump to the currently selected OSC8 hyperlink.
ESC-u Undo (toggle) search highlighting.
ESC-U Clear search highlighting.
&_p_a_t_t_e_r_n * Display only matching lines.
---------------------------------------------------
A search pattern may begin with one or more of:
^N or ! Search for NON-matching lines.
^E or * Search multiple files (pass thru END OF FILE).
^F or @ Start search at FIRST file (for /) or last file (for ?).
^K Highlight matches, but don't move (KEEP position).
^R Don't use REGULAR EXPRESSIONS.
^S _n Search for match in _n-th parenthesized subpattern.
^W WRAP search if no match found.
^L Enter next character literally into pattern.
---------------------------------------------------------------------------
JJUUMMPPIINNGG
g < ESC-< * Go to first line in file (or line _N).
G > ESC-> * Go to last line in file (or line _N).
p % * Go to beginning of file (or _N percent into file).
t * Go to the (_N-th) next tag.
T * Go to the (_N-th) previous tag.
{ ( [ * Find close bracket } ) ].
} ) ] * Find open bracket { ( [.
ESC-^F _<_c_1_> _<_c_2_> * Find close bracket _<_c_2_>.
ESC-^B _<_c_1_> _<_c_2_> * Find open bracket _<_c_1_>.
---------------------------------------------------
Each "find close bracket" command goes forward to the close bracket
matching the (_N-th) open bracket in the top line.
Each "find open bracket" command goes backward to the open bracket
matching the (_N-th) close bracket in the bottom line.
m_<_l_e_t_t_e_r_> Mark the current top line with <letter>.
M_<_l_e_t_t_e_r_> Mark the current bottom line with <letter>.
'_<_l_e_t_t_e_r_> Go to a previously marked position.
'' Go to the previous position.
^X^X Same as '.
ESC-m_<_l_e_t_t_e_r_> Clear a mark.
---------------------------------------------------
A mark is any upper-case or lower-case letter.
Certain marks are predefined:
^ means beginning of the file
$ means end of the file
---------------------------------------------------------------------------
CCHHAANNGGIINNGG FFIILLEESS
:e [_f_i_l_e] Examine a new file.
^X^V Same as :e.
:n * Examine the (_N-th) next file from the command line.
:p * Examine the (_N-th) previous file from the command line.
:x * Examine the first (or _N-th) file from the command line.
^O^O Open the currently selected OSC8 hyperlink.
:d Delete the current file from the command line list.
= ^G :f Print current file name.
---------------------------------------------------------------------------
MMIISSCCEELLLLAANNEEOOUUSS CCOOMMMMAANNDDSS
-_<_f_l_a_g_> Toggle a command line option [see OPTIONS below].
--_<_n_a_m_e_> Toggle a command line option, by name.
__<_f_l_a_g_> Display the setting of a command line option.
___<_n_a_m_e_> Display the setting of an option, by name.
+_c_m_d Execute the less cmd each time a new file is examined.
!_c_o_m_m_a_n_d Execute the shell command with $SHELL.
#_c_o_m_m_a_n_d Execute the shell command, expanded like a prompt.
|XX_c_o_m_m_a_n_d Pipe file between current pos & mark XX to shell command.
s _f_i_l_e Save input to a file.
v Edit the current file with $VISUAL or $EDITOR.
V Print version number of "less".
---------------------------------------------------------------------------
OOPPTTIIOONNSS
Most options may be changed either on the command line,
or from within less by using the - or -- command.
Options may be given in one of two forms: either a single
character preceded by a -, or a name preceded by --.
-? ........ --help
Display help (from command line).
-a ........ --search-skip-screen
Search skips current screen.
-A ........ --SEARCH-SKIP-SCREEN
Search starts just after target line.
-b [_N] .... --buffers=[_N]
Number of buffers.
-B ........ --auto-buffers
Don't automatically allocate buffers for pipes.
-c ........ --clear-screen
Repaint by clearing rather than scrolling.
-d ........ --dumb
Dumb terminal.
-D xx_c_o_l_o_r . --color=xx_c_o_l_o_r
Set screen colors.
-e -E .... --quit-at-eof --QUIT-AT-EOF
Quit at end of file.
-f ........ --force
Force open non-regular files.
-F ........ --quit-if-one-screen
Quit if entire file fits on first screen.
-g ........ --hilite-search
Highlight only last match for searches.
-G ........ --HILITE-SEARCH
Don't highlight any matches for searches.
-h [_N] .... --max-back-scroll=[_N]
Backward scroll limit.
-i ........ --ignore-case
Ignore case in searches that do not contain uppercase.
-I ........ --IGNORE-CASE
Ignore case in all searches.
-j [_N] .... --jump-target=[_N]
Screen position of target lines.
-J ........ --status-column
Display a status column at left edge of screen.
-k _f_i_l_e ... --lesskey-file=_f_i_l_e
Use a compiled lesskey file.
-K ........ --quit-on-intr
Exit less in response to ctrl-C.
-L ........ --no-lessopen
Ignore the LESSOPEN environment variable.
-m -M .... --long-prompt --LONG-PROMPT
Set prompt style.
-n ......... --line-numbers
Suppress line numbers in prompts and messages.
-N ......... --LINE-NUMBERS
Display line number at start of each line.
-o [_f_i_l_e] .. --log-file=[_f_i_l_e]
Copy to log file (standard input only).
-O [_f_i_l_e] .. --LOG-FILE=[_f_i_l_e]
Copy to log file (unconditionally overwrite).
-p _p_a_t_t_e_r_n . --pattern=[_p_a_t_t_e_r_n]
Start at pattern (from command line).
-P [_p_r_o_m_p_t] --prompt=[_p_r_o_m_p_t]
Define new prompt.
-q -Q .... --quiet --QUIET --silent --SILENT
Quiet the terminal bell.
-r -R .... --raw-control-chars --RAW-CONTROL-CHARS
Output "raw" control characters.
-s ........ --squeeze-blank-lines
Squeeze multiple blank lines.
-S ........ --chop-long-lines
Chop (truncate) long lines rather than wrapping.
-t _t_a_g .... --tag=[_t_a_g]
Find a tag.
-T [_t_a_g_s_f_i_l_e] --tag-file=[_t_a_g_s_f_i_l_e]
Use an alternate tags file.
-u -U .... --underline-special --UNDERLINE-SPECIAL
Change handling of backspaces, tabs and carriage returns.
-V ........ --version
Display the version number of "less".
-w ........ --hilite-unread
Highlight first new line after forward-screen.
-W ........ --HILITE-UNREAD
Highlight first new line after any forward movement.
-x [_N[,...]] --tabs=[_N[,...]]
Set tab stops.
-X ........ --no-init
Don't use termcap init/deinit strings.
-y [_N] .... --max-forw-scroll=[_N]
Forward scroll limit.
-z [_N] .... --window=[_N]
Set size of window.
-" [_c[_c]] . --quotes=[_c[_c]]
Set shell quote characters.
-~ ........ --tilde
Don't display tildes after end of file.
-# [_N] .... --shift=[_N]
Set horizontal scroll amount (0 = one half screen width).
--exit-follow-on-close
Exit F command on a pipe when writer closes pipe.
--file-size
Automatically determine the size of the input file.
--follow-name
The F command changes files if the input file is renamed.
--header=[_L[,_C[,_N]]]
Use _L lines (starting at line _N) and _C columns as headers.
--incsearch
Search file as each pattern character is typed in.
--intr=[_C]
Use _C instead of ^X to interrupt a read.
--lesskey-context=_t_e_x_t
Use lesskey source file contents.
--lesskey-src=_f_i_l_e
Use a lesskey source file.
--line-num-width=[_N]
Set the width of the -N line number field to _N characters.
--match-shift=[_N]
Show at least _N characters to the left of a search match.
--modelines=[_N]
Read _N lines from the input file and look for vim modelines.
--mouse
Enable mouse input.
--no-keypad
Don't send termcap keypad init/deinit strings.
--no-histdups
Remove duplicates from command history.
--no-number-headers
Don't give line numbers to header lines.
--no-search-header-lines
Searches do not include header lines.
--no-search-header-columns
Searches do not include header columns.
--no-search-headers
Searches do not include header lines or columns.
--no-vbell
Disable the terminal's visual bell.
--redraw-on-quit
Redraw final screen when quitting.
--rscroll=[_C]
Set the character used to mark truncated lines.
--save-marks
Retain marks across invocations of less.
--search-options=[EFKNRW-]
Set default options for every search.
--show-preproc-errors
Display a message if preprocessor exits with an error status.
--proc-backspace
Process backspaces for bold/underline.
--PROC-BACKSPACE
Treat backspaces as control characters.
--proc-return
Delete carriage returns before newline.
--PROC-RETURN
Treat carriage returns as control characters.
--proc-tab
Expand tabs to spaces.
--PROC-TAB
Treat tabs as control characters.
--status-col-width=[_N]
Set the width of the -J status column to _N characters.
--status-line
Highlight or color the entire line containing a mark.
--use-backslash
Subsequent options use backslash as escape char.
--use-color
Enables colored text.
--wheel-lines=[_N]
Each click of the mouse wheel moves _N lines.
--wordwrap
Wrap lines at spaces.
---------------------------------------------------------------------------
LLIINNEE EEDDIITTIINNGG
These keys can be used to edit text being entered
on the "command line" at the bottom of the screen.
RightArrow ..................... ESC-l ... Move cursor right one character.
LeftArrow ...................... ESC-h ... Move cursor left one character.
ctrl-RightArrow ESC-RightArrow ESC-w ... Move cursor right one word.
ctrl-LeftArrow ESC-LeftArrow ESC-b ... Move cursor left one word.
HOME ........................... ESC-0 ... Move cursor to start of line.
END ............................ ESC-$ ... Move cursor to end of line.
BACKSPACE ................................ Delete char to left of cursor.
DELETE ......................... ESC-x ... Delete char under cursor.
ctrl-BACKSPACE ESC-BACKSPACE ........... Delete word to left of cursor.
ctrl-DELETE .... ESC-DELETE .... ESC-X ... Delete word under cursor.
ctrl-U ......... ESC (MS-DOS only) ....... Delete entire line.
UpArrow ........................ ESC-k ... Retrieve previous command line.
DownArrow ...................... ESC-j ... Retrieve next command line.
TAB ...................................... Complete filename & cycle.
SHIFT-TAB ...................... ESC-TAB Complete filename & reverse cycle.
ctrl-L ................................... Complete filename, list all.
+1 -1
View File
@@ -1 +1 @@
0.8.10
0.8.11
+68
View File
@@ -0,0 +1,68 @@
using System.Runtime.InteropServices;
namespace QuanTAlib;
/// <summary>
/// Common lifecycle surface for host-driven signal primitives.
/// Unlike <see cref="AbstractBase"/>, this base does not own indicator inputs,
/// historical priming or batch series updates. It publishes position updates;
/// predicate and order primitives may define their own typed series bases.
/// </summary>
public abstract class SignalBase : ISignalPublisher, IDisposable
{
public int WarmupPeriod { get; protected init; }
public TPosition Last { get; protected set; }
public abstract bool IsHot { get; }
public event TPositionPublishedHandler? Pub;
protected void PubEvent(TPosition position, bool isNew = true)
{
Pub?.Invoke(this, new TPositionEventArgs { Position = position, IsNew = isNew });
}
public abstract TPosition Update(TPosition input, bool isNew = true);
public abstract void Reset();
public void Dispose()
{
Dispose(disposing: true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
}
}
/// <summary>
/// Event arguments for timestamped position updates.
/// </summary>
[StructLayout(LayoutKind.Auto)]
public readonly struct TPositionEventArgs : IEquatable<TPositionEventArgs>
{
public TPosition Position { get; init; }
public bool IsNew { get; init; }
public bool Equals(TPositionEventArgs other) =>
Position.Equals(other.Position) && IsNew == other.IsNew;
public override bool Equals(object? obj) =>
obj is TPositionEventArgs other && Equals(other);
public override int GetHashCode() => HashCode.Combine(Position, IsNew);
public static bool operator ==(TPositionEventArgs left, TPositionEventArgs right) => left.Equals(right);
public static bool operator !=(TPositionEventArgs left, TPositionEventArgs right) => !left.Equals(right);
}
public delegate void TPositionPublishedHandler(object? sender, in TPositionEventArgs args);
public interface ISignalPublisher
{
event TPositionPublishedHandler? Pub;
}
@@ -0,0 +1,35 @@
namespace QuanTAlib.Tests;
public class TOrderTests
{
[Fact]
public void Constructor_SetsProperties()
{
var order = new TOrder(12345, OrderAction.BTO, true);
Assert.Equal(12345, order.Time);
Assert.Equal(OrderAction.BTO, order.Action);
Assert.True(order.IsHot);
}
[Fact]
public void OrderAction_ContainsExpectedActions()
{
Assert.Equal(2, (sbyte)OrderAction.BTO);
Assert.Equal(1, (sbyte)OrderAction.BTC);
Assert.Equal(0, (sbyte)OrderAction.NIL);
Assert.Equal(-1, (sbyte)OrderAction.STC);
Assert.Equal(-2, (sbyte)OrderAction.STO);
}
[Fact]
public void RecordEquality_UsesAllProperties()
{
var first = new TOrder(12345, OrderAction.STC, true);
var same = new TOrder(12345, OrderAction.STC, true);
var different = new TOrder(12345, OrderAction.STO, true);
Assert.Equal(first, same);
Assert.NotEqual(first, different);
}
}
+21
View File
@@ -0,0 +1,21 @@
using System.Runtime.InteropServices;
namespace QuanTAlib;
/// <summary>
/// Order action represented by a strategy signal. Execution remains host-owned.
/// </summary>
public enum OrderAction : sbyte
{
BTO = 2,
BTC = 1,
NIL = 0,
STC = -1,
STO = -2,
}
/// <summary>
/// Timestamped order action signal.
/// </summary>
[StructLayout(LayoutKind.Auto)]
public readonly record struct TOrder(long Time, OrderAction Action, bool IsHot);
@@ -0,0 +1,33 @@
namespace QuanTAlib.Tests;
public class TPositionTests
{
[Fact]
public void Constructor_SetsProperties()
{
var position = new TPosition(12345, Direction.Long, true);
Assert.Equal(12345, position.Time);
Assert.Equal(Direction.Long, position.Direction);
Assert.True(position.IsHot);
}
[Fact]
public void Direction_ContainsLongFlatAndShort()
{
Assert.Equal(-1, (sbyte)Direction.Short);
Assert.Equal(0, (sbyte)Direction.Flat);
Assert.Equal(1, (sbyte)Direction.Long);
}
[Fact]
public void RecordEquality_UsesAllProperties()
{
var first = new TPosition(12345, Direction.Flat, true);
var same = new TPosition(12345, Direction.Flat, true);
var different = new TPosition(12345, Direction.Long, true);
Assert.Equal(first, same);
Assert.NotEqual(first, different);
}
}
+16
View File
@@ -0,0 +1,16 @@
using System.Runtime.InteropServices;
namespace QuanTAlib;
public enum Direction : sbyte
{
Short = -1,
Flat = 0,
Long = 1,
}
/// <summary>
/// Timestamped long, flat, or short position state.
/// </summary>
[StructLayout(LayoutKind.Auto)]
public readonly record struct TPosition(long Time, Direction Direction, bool IsHot);
+527
View File
@@ -0,0 +1,527 @@
# Strategy Primitives Specification
Status: Proposed
## Purpose
This directory defines the pluggable signal primitives that sit above QuanTAlib indicators and below a host execution platform such as Quantower or Lean.
The boundary is **target exposure and trading intent**. These primitives may produce conditions, events, allocations, and protective levels. They must not place orders, simulate fills, model slippage, manage broker connections, or own a backtesting loop.
The pipeline is:
```text
Transforms / Indicators
|
v
Comparative Predicates
|
v
Temporal Triggers
|
v
Logic Combinators
|
v
Position State Machine ---> StrategyIntent
```
Layer 1 remains in the existing indicator and transform namespaces. This directory owns Layers 2 through 4 and the contracts needed to feed a host-owned Layer 5 position state machine.
## Repository Baseline and Non-Duplication Rules
The current library already contains the indicator-side contracts that the signal primitive layer must build on. The signal primitive spec must not duplicate or re-define these behaviors with a different vocabulary.
Relevant existing abstractions:
- `lib/core/AbstractBase.cs`: owns the base indicator lifecycle contract (`Name`, `WarmupPeriod`, `IsHot`, `Prime`, `Update`, `Reset`, `Pub`).
- `lib/core/BiInputIndicatorBase.cs`: demonstrates the canonical `isNew` correction and rollback pattern for bar updates, including snapshot/restore behaviors.
- `lib/core/ringbuffer/RingBuffer.cs`: provides the fixed-capacity, zero-allocation state container pattern for rolling windows and running sums.
- `lib/core/tvalue/tvalue.cs`: defines `TValue` as the timestamped streaming value type used throughout the library.
- `lib/core/tseries/ITValuePublisher.cs`: defines the event-publishing contract used by indicators to emit value updates.
The design goal is therefore not to duplicate the indicator lifecycle. Signal primitives will add their own typed outputs and state only where required for predicates, triggers, composition, and host-neutral intent. The lifecycle behavior for those primitives remains a Phase 1 implementation concern.
## Ecosystem Context
The design deliberately combines useful ideas from established quantitative ecosystems without importing their unsuitable trade-offs:
| Ecosystem | Relevant strength | Constraint for QuanTAlib |
| :--- | :--- | :--- |
| TradingView Pine Script | Mature temporal primitives such as `crossover`, `barssince`, and `valuewhen`. | Series history references are expressive, but rolling buffers are not a zero-allocation streaming model. |
| Backtrader and Lean | Operator-based composition, composite indicators, event-driven windows, and reusable indicator graphs. | Their graph and window abstractions must be narrowed to fixed O(1) state for hot-path use here. |
| VectorBT | Fast batch signal post-processing such as entry/exit cleaning, first-signal selection, and holding limits. | Its T x N boolean-mask model is batch-only and cannot define the live rollback contract. |
| NautilusTrader | Event-driven state nodes backed by a systems-language runtime. | Its event/state separation is a useful model; QuanTAlib keeps the execution boundary outside the library. |
The target is declarative algebra over streaming components, not a general-purpose backtester.
## Design Requirements
Every primitive MUST satisfy these requirements:
1. Streaming updates use O(1) state per primitive and do not allocate on the hot path.
2. `IsHot` propagates recursively through composed components.
3. `isNew` updates are deterministic for both confirmed bars and forming-bar ticks.
4. A forming-bar update can be rolled back without leaking state into the next bar.
5. Components can be composed without a custom strategy loop in user code.
6. The output is deterministic for the same input stream and lifecycle sequence.
7. Execution remains outside this library.
## Core Value Types
The C# API should use small value types for hot-path results:
```csharp
public enum Direction : sbyte
{
Short = -1,
Flat = 0,
Long = 1
}
public readonly record struct TPosition(long Time, Direction Direction, bool IsHot);
public enum OrderAction : sbyte
{
BTO = 2,
BTC = 1,
NIL = 0,
STC = -1,
STO = -2
}
public readonly record struct TOrder(long Time, OrderAction Action, bool IsHot);
```
`SizeFactor` is normalized to `[0, 1]`. A host may translate it to quantity, notional, or risk budget. A primitive must not assume account size, leverage, margin, or broker semantics.
## Lifecycle Contract
### Confirmed and working state
Each stateful primitive has two logical snapshots:
- **Confirmed state**: state at the last completed bar.
- **Working state**: state after applying the current forming-bar update.
For `isNew == false`, update only the working state. Repeated ticks for the same bar replace the working state rather than advancing confirmed history.
For `isNew == true`:
1. Promote the previous working state to confirmed state.
2. Start the new working state from the promoted confirmed state.
3. Apply the new bar value.
A host may expose an explicit `Commit()` operation if its feed semantics distinguish a final tick from the first tick of the next bar. The implementation must document which convention it uses and test it with repeated intra-bar updates.
### Priming
`IsHot` is false until all required input history is available. A composite is hot only when every child required for its current evaluation is hot.
A strategy state machine MUST remain `Flat` with zero size and no brackets until its complete dependency graph is hot. Warm-up must never produce an entry or exit event.
### Reset
Every stateful primitive MUST support reset to its initial, cold state. Reset clears confirmed and working snapshots, previous values, counters, and cached event results.
## Layer 2: Predicates
Predicates convert indicator values into boolean states or normalized values. They do not create one-shot events.
### Required primitives
| Primitive | Meaning |
| :--- | :--- |
| `LessThan` | Test whether the left value is less than the right value. The right operand may be a scalar or a streaming value. |
| `GreaterThan` | Test whether the left value is greater than the right value. The right operand may be a scalar or a streaming value. |
| `Equal` | Test whether two values are equal within an optional epsilon. The default epsilon is the documented library comparison tolerance. |
| `InsideChannel` | Test whether a value is inside or outside channel bounds. |
| `OutsideChannel` | Test whether a value is above the upper or below the lower bound. |
| `ChannelPosition` | Return normalized position within channel bounds. |
| `IsRising` | Test whether a value is increasing over the requested observation. |
| `IsFalling` | Test whether a value is decreasing over the requested observation. |
| `StrictMonotonic` | Require every adjacent observation to move strictly in one direction. |
| `QuantileRank` | Return the current value's rank within a fixed lookback window. |
| `ZScoreNormalize` | Convert a value into a normalized z-score output. |
`LessThan`, `GreaterThan`, and `Equal` are the canonical comparison functions. Each accepts either a scalar or a streaming value as its right operand, so separate comparison primitives are unnecessary. The scalar overload must use a specialized allocation-free path and must not create a constant child node on every update.
The initial API may expose factory methods instead of operators. Operator syntax is a surface goal, not permission to weaken type safety or introduce hidden allocations. Where the type system permits it, `<` maps to `LessThan`, `>` maps to `GreaterThan`, and `==` may map to `Equal` on a library-owned expression type. `<=` and `>=` are not required public predicates; they remain available internally for trigger boundary definitions.
Example target syntax in C#:
```csharp
var bullish = fast > slow;
var oversold = rsi < 30.0;
var nearMean = Equal(source, mean, epsilon: 1e-8);
var inChannel = InsideChannel(source, lower, upper);
```
Each predicate exposes its current normalized `TValue` through an allocation-free update method. Predicate values are expected to remain in the inclusive range `[0, 1]`; producers must reject or explicitly handle values outside that range rather than silently clamp them. A predicate must not advance a child indicator implicitly; input ownership and update ordering must be explicit. Directional position signals use `TPosition`; order action signals use `TOrder`. A future host-intent layer may add allocation and bracket information.
Mathematical definitions for the normalized predicates are:
```text
Equal: |A_t - B_t| <= epsilon, where epsilon uses the library default when omitted
InsideChannel: Lower_t <= A_t <= Upper_t
OutsideChannel: A_t > Upper_t or A_t < Lower_t
ChannelPosition: (A_t - Lower_t) / (Upper_t - Lower_t)
IsRising: A_t > A_(t-k)
IsFalling: A_t < A_(t-k)
StrictMonotonic: A_(t-i+1) > A_(t-i), for every i in [1, k]
QuantileRank: rank(A_t) / N
ZScoreNormalize: (A_t - mean_t) / standard_deviation_t
```
The default epsilon must be a named, documented library constant. It must not be `double.Epsilon`, which is a machine-level spacing value and is generally unsuitable as a financial comparison tolerance. Callers may override it when the scale or precision of the input requires a different tolerance. `Equal` is a value predicate, not C# object identity or structural equality.
Division by a zero-width channel and a zero-variance z-score must have explicit policies. The default is `IsHot = false` for the normalized result and no event until the denominator becomes valid.
## Layer 3: Temporal Triggers
Triggers convert current and prior predicate or value states into one-shot events.
### Required primitives
| Primitive | Meaning |
| :--- | :--- |
| `CrossOver` | Previous left was less than or equal to right; current left is greater. |
| `CrossUnder` | Previous left was greater than or equal to right; current left is less. |
| `BecameTrue` | Predicate changed from false to true. |
| `BecameFalse` | Predicate changed from true to false. |
| `BarsSince` | Number of confirmed bars since a predicate was true. |
| `ValueWhen` | Capture the latest value when a predicate fires. |
| `OccurredWithin` | Test whether an event occurred within a confirmed window. |
| `CountOccurrences` | Count event firings over a fixed lookback. |
| `HoldFor` | Fire after a predicate remains true for N bars. |
| `PivotExtremum` | Confirm a local high or low after the required right-side bars close. |
| `DivergenceDetector` | Compare structural price and indicator swings for regular or hidden divergence. |
Triggers MUST define equality behavior, cold-start behavior, and whether an event can fire during an unconfirmed tick. The default event policy is:
- Events may be visible while the current bar is forming.
- An unconfirmed event must be reversible.
- A confirmed event may advance strategy state only through the state machine lifecycle contract.
A crossover must use a confirmed previous sample and a working current sample. It must not use a previous intra-bar tick as the prior bar value.
`ValueWhen` must define occurrence numbering (`0` means the most recent event), and `PivotExtremum` must disclose its confirmation delay. A pivot cannot be reported as confirmed until all `right_bars` observations are confirmed; it must never leak future information into a live signal.
## Layer 4: Logic Combinators
Combinators compose predicates and triggers while preserving hot-state and rollback semantics.
### Required primitives
| Primitive | Meaning |
| :--- | :--- |
| `All` / `And` | Every child is true. |
| `Any` / `Or` | At least one child is true. |
| `KOfN` | At least K of N children are true. |
| `RegimeFork` | Select a branch according to a regime predicate. |
| `Inhibit` | Suppress a trigger while a guard is true. |
| `Debounce` | Prevent repeated events during a cooldown window. |
| `FirstSignalOnly` | Emit the first entry event and suppress later entries until an exit resets the gate. |
| `PriorityCascade` | Select the first eligible event by declared priority. |
`&`, `|`, and `!` may be provided for compatible C# predicate types. Trigger composition must be explicit where boolean algebra would hide event semantics. For example, `trigger & filter` means the trigger fires only when the filter is true; it does not turn the trigger into a persistent state.
Combinators MUST:
- Short-circuit only when doing so cannot change child lifecycle state.
- Evaluate child updates in a deterministic declaration order.
- Report `IsHot` as the conjunction of required child readiness.
- Snapshot internal counters and cooldowns for forming-bar rollback.
`RegimeFork` routes intent rather than merely combining booleans. For example, an `ADX > 25` regime may select a momentum branch while the alternate branch handles range conditions. `PriorityCascade` is evaluated in declaration order so risk overrides, such as a volatility shock stop, mask lower-priority profit-taking rules.
The boolean algebra target is:
```csharp
var entry = CrossOver(fast, slow) & (rsi < 30.0) & volumeAboveAverage;
var cleanEntry = FirstSignalOnly(entry, exit);
var protectedEntry = Inhibit(cleanEntry, newsGuard);
```
Python adapters should expose equivalent factories and operator overloads where Python's operand types make the result unambiguous.
## O(1) State Models
The following state budgets are normative for the first implementation:
| Primitive family | Required state |
| :--- | :--- |
| `LessThan`, `GreaterThan`, and `Equal` predicates | No history beyond child values. |
| `CrossOver`, `CrossUnder`, `BecameTrue`, `BecameFalse` | Previous confirmed sample plus current working sample. |
| `BarsSince`, `OccurredWithin`, `HoldFor` | One fixed-width bar counter and one hot flag. |
| `ValueWhen` | One latched value, presence flag, and event occurrence state. |
| `CountOccurrences` | Fixed-size ring buffer and count; the lookback is fixed at construction. |
| `PivotExtremum` | Ring buffer of `left_bars + right_bars + 1` values. |
| `DivergenceDetector` | Fixed-size swing registers and the configured lookback state. |
| `All`, `Any`, `KOfN` | Immutable child references plus scalar aggregate counters. |
| `Debounce` | One cooldown counter and one confirmed/working event state. |
| `FirstSignalOnly` | One gate state reset by the configured exit event. |
No primitive may grow a history collection in response to input. A ring buffer is allowed only when its capacity is fixed during construction and its storage is owned by the component. Batch-only conveniences such as VectorBT-style masks belong in adapters, not in the streaming core.
## Host-Owned Position State Machine
A future host-neutral state machine may consume Layer 3 and Layer 4 outputs and emit a host-facing intent. It must not execute orders.
The state machine owns only logical position state:
- `Flat`, `Long`, or `Short`.
- Entry reference price or host-provided reference.
- Allocation or conviction factor.
- Stop-loss and take-profit intent.
- Confirmed and working snapshots for rollback.
Before priming, it emits a flat, zero-size intent with no brackets:
```csharp
Direction.Flat, 0.0, null, null
```
The host owns order reconciliation, fills, partial fills, rejected orders, realized position, slippage, commissions, and broker communication. The state machine must accept host position feedback rather than assuming every intent was filled.
## C# and Python Surface
C# is the reference implementation for zero-allocation streaming behavior. Python should expose the same conceptual graph for batch and streaming users:
```python
entry = crossover(fast, slow) & (rsi < 30.0)
exit = crossunder(fast, slow)
strategy = strategy_pipeline(entry_long=entry, exit_long=exit, risk_stop=atr_stop)
intent = strategy.update(bar, is_new=True)
```
Python adapters may use native extensions or Python objects at the boundary, but the native streaming core must retain O(1) state and avoid per-update heap allocation. Operator overloads should preserve the same semantics as the C# surface and must not silently evaluate indicators twice.
## Allocation and Performance Rules
- No LINQ, closures, boxing, or per-update collection creation in native hot paths.
- Child components are wired during construction, not discovered during updates.
- Composite child storage is immutable after construction.
- Counters use fixed-width integer fields with documented overflow behavior.
- Optional values use value types or explicit presence flags in hot paths.
- Diagnostics and tracing are opt-in and must not affect signal semantics.
## Testing Requirements
Every primitive requires tests for:
1. Cold, warming, hot, and reset states.
2. Exact equality at threshold and crossover boundaries.
3. Repeated unconfirmed ticks that oscillate around a boundary.
4. Rollback after an intra-bar trigger that is absent at bar close.
5. Confirmed event behavior across the next bar.
6. Composite short-circuit and evaluation ordering.
7. Zero allocation after construction for representative update loops.
8. C# and Python parity for the same deterministic input stream.
Property-based tests should cover arbitrary tick sequences within a bar and compare a rollback-enabled implementation with a reference model that recomputes the current bar from confirmed state.
## Phased Implementation Plan
The implementation should proceed as small, independently verifiable increments. Each phase produces a usable capability and has an explicit exit gate. No phase may introduce order execution, fill simulation, slippage, broker communication, or a general-purpose backtesting loop.
### Phase 0: API and Boundary Review
**Goal:** Freeze the vocabulary and ownership boundaries before adding code.
**Status:** Complete as an API and boundary decision record. No signal primitive implementation is included in Phase 0.
**Deliverables:**
- Signal primitives belong under `QuanTAlib.Signals`; indicator and transform implementations remain in their existing namespaces under `lib/*`.
- Primitives reuse the established indicator vocabulary: `IsHot`, `WarmupPeriod`, `Reset`, `Update`, and `isNew`. They do not inherit `AbstractBase` merely to gain indicator behavior, and they do not advance child indicators implicitly.
- The host updates indicators first; primitives then consume their current values. A primitive's update contract must make input ownership and update ordering explicit.
- `LessThan`, `GreaterThan`, and `Equal` are the canonical comparison predicates. Scalar and streaming right operands use the same semantics; `<` and `>` are optional operator facades on library-owned expression types.
- `Equal` accepts an optional epsilon and uses a documented library default when omitted. `<=` and `>=` remain internal boundary relations for crossover definitions rather than public predicate types.
- Python adapters use the same names and semantics (`less_than`, `greater_than`, `equal`, `is_new`, `is_hot`, and `reset`) without introducing a second execution or state model.
**Exit gate:** API review confirms that every proposed type has one owner, one update contract, no execution responsibility, and no duplicate lifecycle semantics versus the existing indicator infrastructure.
### Phase 1: Lifecycle Kernel
**Goal:** Establish deterministic hot/working/confirmed state behavior using the library's established lifecycle pattern.
**Repository baseline:** the indicator lifecycle exists in `AbstractBase`, with concrete rollback behavior demonstrated by `BiInputIndicatorBase` and `RingBuffer`. A signal-specific lifecycle kernel does not yet exist and must be designed in Phase 1 without duplicating indicator responsibilities.
**Deliverables:**
- Reuse and clarify the internal lifecycle contract with `IsHot`, `Reset`, confirmed state, and working state.
- Snapshot helpers for scalar values, counters, optional values, and event flags, following the same patterns already used in `BiInputIndicatorBase` and `RingBuffer`.
- Explicit behavior for `isNew == true` and `isNew == false` updates that matches the existing `AbstractBase` and ring-buffer rollback conventions.
- Cold-start behavior and warm-up propagation through a component graph, with no entry or exit intent before the full dependency graph is hot.
- Allocation and mutation benchmarks for an empty lifecycle node, measured against the current hot-path conventions of `TValue`, `RingBuffer`, and the existing indicator implementations.
**Tests:**
- Repeated forming-bar updates replace working state without mutating confirmed history.
- New-bar updates promote working state exactly once and preserve the prior confirmed snapshot.
- Reset returns all state to cold.
- A cold graph cannot emit a signal or non-flat intent.
- A comparison against the existing indicator lifecycle tests confirms the signal kernel does not duplicate indicator behavior.
**Exit gate:** Lifecycle tests pass across repeated tick sequences, the kernel remains compatible with the existing `AbstractBase`/`RingBuffer` conventions, and there is no duplicate state machine competing with the repository's current lifecycle model.
### Phase 2: Core Predicates
**Goal:** Implement allocation-free continuous states and normalized metrics.
**Deliverables:**
- `LessThan` and `GreaterThan` with scalar and streaming right-operand overloads.
- `Equal` with an optional non-negative epsilon and a documented default.
- `InsideChannel`, `OutsideChannel`, and `ChannelPosition` with zero-width policy.
- `IsRising`, `IsFalling`, and `StrictMonotonic` using fixed history state.
- `ZScoreNormalize` using a numerically stable fixed-state accumulator.
- `QuantileRank` only when its fixed-capacity storage and update policy are defined.
**Tests:**
- Boundary equality, NaN/infinite inputs, cold values, and zero denominators.
- Predicate parity against straightforward reference calculations.
- No child indicator is updated implicitly.
**Exit gate:** Core predicates are deterministic, hot-state aware, and allocation-free in representative streaming loops.
### Phase 3: Basic Temporal Triggers
**Goal:** Convert continuous states into reversible one-shot events.
**Deliverables:**
- `CrossOver` and `CrossUnder` with confirmed previous samples.
- `BecameTrue` and `BecameFalse`.
- Event result type carrying `Value`, `IsHot`, and event/confirmation status if required by the host.
- Forming-bar rollback for every edge detector.
**Tests:**
- Equality before a cross and equality on the current sample.
- Cross, uncross, recross, and repeated intra-bar oscillation.
- No event during warm-up.
- A forming-bar event disappears when the bar closes without the event.
**Exit gate:** The same input stream produces identical results under scalar replay and tick-by-tick updates.
### Phase 4: Temporal Memory and Structural Events
**Goal:** Support event sequencing and delayed structural confirmation.
**Deliverables:**
- `BarsSince`, `OccurredWithin`, `CountOccurrences`, and `HoldFor`.
- `ValueWhen` with occurrence indexing and presence state.
- `PivotExtremum` with explicit right-bar confirmation delay.
- `DivergenceDetector` only after swing representation and lookback memory are specified.
**Tests:**
- Counter behavior on event, non-event, reset, and overflow boundaries.
- Value latching on the exact event bar.
- Pivot confirmation never uses unconfirmed future data.
- Structural triggers roll back pending candidates correctly.
**Exit gate:** Every memory primitive has a fixed state budget, documented confirmation timing, and rollback coverage.
### Phase 5: Boolean Gates and Signal Hygiene
**Goal:** Compose conditions and events without semantic ambiguity.
**Deliverables:**
- `All` / `And`, `Any` / `Or`, and `KOfN`.
- `Inhibit` and `Debounce`.
- `FirstSignalOnly` with an exit-controlled reset.
- Deterministic child ordering and lifecycle propagation.
- Operator syntax where the type system can preserve predicate-versus-trigger meaning.
**Tests:**
- Empty and singleton composites, invalid K values, and short-circuit behavior.
- Child evaluation order and no duplicate child updates.
- Cooldown rollback and first-entry gate rollback.
- Composite hot-state behavior with mixed warm-up periods.
**Exit gate:** Compound graphs behave identically to a reference evaluator and remain zero-allocation after construction.
### Phase 6: Regime Routing and Priority
**Goal:** Add contextual branch selection and conflict resolution.
**Deliverables:**
- `RegimeFork` for selecting one active branch.
- `PriorityCascade` for ordered risk and signal overrides.
- Explicit behavior when multiple branches are hot, cold, or simultaneously eligible.
- Diagnostics that are opt-in and do not mutate signal state.
**Tests:**
- Regime transitions on confirmed and forming bars.
- Branch state isolation and reset behavior.
- Priority masking and deterministic tie handling.
- No evaluation of inactive branches when lifecycle semantics permit skipping.
**Exit gate:** Regime and priority behavior is deterministic under replay and does not create hidden execution semantics.
### Phase 7: Strategy Intent Boundary
**Goal:** Produce host-consumable target exposure without placing trades.
**Deliverables:**
- Host-neutral `Direction` and host-intent output.
- A position state machine for `Flat`, `Long`, and `Short` transitions.
- Priming gate that emits flat, zero-size intent until the full graph is hot.
- Pluggable stop and take-profit intent providers, including ATR-based examples.
- Host position feedback contract for fills, partial fills, rejects, and external position changes.
**Tests:**
- Entry and exit transitions, reversal policy, and repeated identical intents.
- Intra-bar entry rollback and confirmed-bar promotion.
- Bracket recalculation without execution side effects.
- Intent stability when host-reported position differs from requested intent.
**Exit gate:** The state machine emits only deterministic intent values and has no dependency on a broker, order, fill, or account API.
### Phase 8: Python Parity
**Goal:** Expose the same semantics to Python users without weakening the streaming core.
**Deliverables:**
- Python factories and operators for the supported primitive subset.
- Consistent naming, hot-state, reset, and `is_new` semantics.
- Native-backed streaming adapter where performance requires it.
- Batch adapter that reuses the same reference semantics rather than defining a second behavior.
**Tests:**
- C# and Python golden-stream parity.
- Same results for bar-only and forming-tick sequences.
- Python operator precedence and invalid-composition errors.
- Allocation and throughput benchmarks for native and adapter paths.
**Exit gate:** Cross-language parity tests pass for all released primitives and differences are documented where language syntax requires them.
### Phase 9: Hardening and Release Readiness
**Goal:** Make the primitive layer safe to evolve and suitable for production hosts.
**Deliverables:**
- Full property-based tests for arbitrary intra-bar tick sequences.
- Allocation regression tests and benchmark baselines.
- Documentation examples for Quantower and Lean-style hosts.
- Versioning and compatibility notes for public interfaces and operator behavior.
- Review of analyzer, security, NativeAOT, and multi-target build behavior.
**Exit gate:** Full solution validation passes, performance budgets are recorded, and the public API has documented compatibility guarantees.
Stateful signal primitives should not proceed beyond their API scaffolding until the Phase 1 lifecycle tests are complete. This staged approach keeps the primitive layer composable without turning QuanTAlib into an execution engine or bloated backtester.
+285 -60
View File
@@ -11,6 +11,12 @@ namespace QuanTAlib;
/// Combines 2-pole IIR core with trimmed-mean volatility estimation.
///
/// Key features: phase control [-100,100], adaptive band tracking, dynamic exponent.
///
/// The 128-sample volatility window uses Index-Linked Sorted Arrays (ILSA): a chronological
/// circular buffer plus two integer rank/position maps kept permanently sorted, so each bar
/// costs one 7-step binary search and a single memmove of 4-byte indices instead of a full
/// re-sort. The middle-65 trimmed mean is maintained as a running sum updated by deterministic
/// boundary-crossing deltas rather than 65 sequential additions.
/// </remarks>
/// <seealso href="Jma.md">Detailed documentation</seealso>
/// <seealso href="jma.pine">Reference Pine Script implementation</seealso>
@@ -18,8 +24,17 @@ namespace QuanTAlib;
public sealed class Jma : AbstractBase
{
private const int VolWindowSize = 128; // volatility history length
private const int VolIndexMask = VolWindowSize - 1;
private const int DevWindowSize = 10; // short SMA length for deviation
private const int JurikTrimCount = 65; // canonical JMA: middle 65 of 128 samples
private const int CoreLo = 32; // ceil((128-65)/2)
private const int CoreHi = CoreLo + JurikTrimCount - 1; // 96
private const int MinVolSamples = 16; // below this, volatility is passed through
// Periodic exact re-sum to bound floating-point drift of the incremental core sum.
private const int SumRefreshInterval = 1024;
// Jurik core parameters derived from period/phase
private readonly double _phaseParam; // 0.5 .. 2.5
private readonly double _logParam; // log(sqrt(L))/log(2) + 2, clamped >= 0
@@ -28,16 +43,27 @@ public sealed class Jma : AbstractBase
private readonly double _logLengthDivider; // Precomputed log(_lengthDivider) for Exp optimization
private readonly double _pExponent; // max(logParam - 2, 0.5)
// Constants for trimmed mean
private const int JurikTrimCount = 65; // canonical JMA: middle 65 of 128 samples
// Buffers
private readonly RingBuffer _devBuffer;
private readonly RingBuffer _volBuffer;
private readonly TValuePublishedHandler _handler;
private readonly ITValuePublisher? _source;
private bool _disposed;
// --- ILSA: three contiguous 128-element arrays (1,536 bytes, L1-resident) ---
private readonly double[] _chrono; // C: chronological circular buffer of volatility values
private readonly int[] _sortedToC; // S_to_C: sorted rank -> chronological position
private readonly int[] _cToSorted; // C_to_S: chronological position -> sorted rank
private int _volCount;
private int _oldestC; // chronological position of the expiring element (valid once full)
private double _coreSum;
private int _sumTicks;
// --- Undo journal: restores the ILSA to the pre-update state for isNew=false replays ---
private bool _undoValid;
private bool _undoWasAppend;
private int _undoOldC, _undoOldS, _undoNewS, _undoOldestC, _undoCount, _undoSumTicks;
private double _undoOldVal, _undoCoreSum;
// Streaming state (current + previous snapshot for isNew=false)
private State _state;
private State _p_state;
@@ -113,7 +139,9 @@ public sealed class Jma : AbstractBase
Name = $"Jma({period},{phase})";
_devBuffer = new RingBuffer(DevWindowSize);
_volBuffer = new RingBuffer(VolWindowSize);
_chrono = GC.AllocateArray<double>(VolWindowSize, pinned: true);
_sortedToC = GC.AllocateArray<int>(VolWindowSize, pinned: true);
_cToSorted = GC.AllocateArray<int>(VolWindowSize, pinned: true);
Reset();
}
@@ -125,16 +153,261 @@ public sealed class Jma : AbstractBase
source.Pub += _handler;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public override void Reset()
{
_state = default;
_p_state = default;
_devBuffer.Clear();
_volBuffer.Clear();
_volCount = 0;
_oldestC = 0;
_coreSum = 0.0;
_sumTicks = 0;
_undoValid = false;
Last = default;
}
#region ILSA volatility window
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private double SortedAt(int rank) => _chrono[_sortedToC[rank]];
/// <summary>Value at <paramref name="rank"/> of the conceptual 127-element array with rank <paramref name="holeS"/> removed.</summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private double GapAt(int rank, int holeS) => SortedAt(rank < holeS ? rank : rank + 1);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private void ResyncReverseMap(int fromRank, int toRank)
{
for (int i = fromRank; i <= toRank; i++)
{
_cToSorted[_sortedToC[i]] = i;
}
}
/// <summary>First rank in [0,count) whose value exceeds <paramref name="value"/>.</summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private int UpperBound(double value, int count)
{
int lo = 0;
int hi = count;
while (lo < hi)
{
int mid = (int)(((uint)lo + (uint)hi) >> 1);
if (SortedAt(mid) > value)
{
hi = mid;
}
else
{
lo = mid + 1;
}
}
return lo;
}
/// <summary>Binary search over the 127-element array that logically skips rank <paramref name="holeS"/>. Exactly 7 iterations.</summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private int UpperBoundWithHole(double value, int holeS)
{
int lo = 0;
int hi = VolWindowSize - 1;
while (lo < hi)
{
int mid = (int)(((uint)lo + (uint)hi) >> 1);
if (GapAt(mid, holeS) > value)
{
hi = mid;
}
else
{
lo = mid + 1;
}
}
return lo;
}
private double RecomputeCoreSum()
{
double sum = 0.0;
for (int i = CoreLo; i <= CoreHi; i++)
{
sum += SortedAt(i);
}
return sum;
}
/// <summary>Pushes one volatility sample and returns the reference volatility (trimmed mean).</summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private double PushVolatility(double value)
=> _volCount < VolWindowSize ? AppendVolatility(value) : ReplaceOldestVolatility(value);
private double AppendVolatility(double value)
{
int n = _volCount;
int newS = UpperBound(value, n);
_undoWasAppend = true;
_undoNewS = newS;
_undoCount = n;
_undoOldestC = _oldestC;
_undoCoreSum = _coreSum;
_undoSumTicks = _sumTicks;
_undoValid = true;
if (n > newS)
{
Array.Copy(_sortedToC, newS, _sortedToC, newS + 1, n - newS);
}
_sortedToC[newS] = n;
_chrono[n] = value;
_volCount = n + 1;
ResyncReverseMap(newS, n);
if (_volCount == VolWindowSize)
{
_oldestC = 0;
_sumTicks = 0;
_coreSum = RecomputeCoreSum();
return _coreSum / JurikTrimCount;
}
return _volCount < MinVolSamples ? value : WarmupTrimmedMean(_volCount);
}
private double ReplaceOldestVolatility(double value)
{
int oldC = _oldestC;
int oldS = _cToSorted[oldC];
double oldVal = _chrono[oldC];
// Deletion delta, evaluated against the current 128-element sorted array.
double deltaRemove = 0.0;
if (oldS <= CoreHi)
{
double displaced = oldS < CoreLo ? SortedAt(CoreLo) : oldVal;
deltaRemove = SortedAt(CoreHi + 1) - displaced;
}
// Insertion rank, and insertion delta against the 127-element post-deletion array.
int newS = UpperBoundWithHole(value, oldS);
double deltaInsert = 0.0;
if (newS <= CoreHi)
{
double entering = newS < CoreLo ? GapAt(CoreLo - 1, oldS) : value;
deltaInsert = entering - GapAt(CoreHi, oldS);
}
_undoWasAppend = false;
_undoOldC = oldC;
_undoOldS = oldS;
_undoNewS = newS;
_undoOldVal = oldVal;
_undoOldestC = oldC;
_undoCount = _volCount;
_undoCoreSum = _coreSum;
_undoSumTicks = _sumTicks;
_undoValid = true;
// Single contiguous shift of 4-byte indices closes the deletion gap and opens the insertion slot.
if (newS <= oldS)
{
if (oldS > newS)
{
Array.Copy(_sortedToC, newS, _sortedToC, newS + 1, oldS - newS);
}
_sortedToC[newS] = oldC;
ResyncReverseMap(newS, oldS);
}
else
{
Array.Copy(_sortedToC, oldS + 1, _sortedToC, oldS, newS - oldS);
_sortedToC[newS] = oldC;
ResyncReverseMap(oldS, newS);
}
_chrono[oldC] = value;
_oldestC = (oldC + 1) & VolIndexMask;
_coreSum += deltaRemove + deltaInsert;
if (++_sumTicks >= SumRefreshInterval)
{
_sumTicks = 0;
_coreSum = RecomputeCoreSum();
}
return _coreSum / JurikTrimCount;
}
/// <summary>Dynamic trim boundaries used while the 128-sample window is still filling.</summary>
private double WarmupTrimmedMean(int count)
{
int slice = (int)Math.Max(5, Math.Round(count * 0.5));
int drop = (count - slice) / 2;
int start = drop < 0 ? 0 : drop;
int end = drop + slice - 1;
if (end >= count)
{
end = count - 1;
}
double sum = 0.0;
for (int i = start; i <= end; i++)
{
sum += SortedAt(i);
}
return sum / (end - start + 1);
}
/// <summary>Reverses the most recent ILSA mutation (intrabar replay support).</summary>
private void UndoVolatility()
{
if (!_undoValid)
{
return;
}
if (_undoWasAppend)
{
int n = _undoCount;
int newS = _undoNewS;
if (n > newS)
{
Array.Copy(_sortedToC, newS + 1, _sortedToC, newS, n - newS);
}
_volCount = n;
ResyncReverseMap(newS, n - 1);
}
else
{
int oldS = _undoOldS;
int newS = _undoNewS;
int oldC = _undoOldC;
if (newS <= oldS)
{
if (oldS > newS)
{
Array.Copy(_sortedToC, newS + 1, _sortedToC, newS, oldS - newS);
}
_sortedToC[oldS] = oldC;
ResyncReverseMap(newS, oldS);
}
else
{
Array.Copy(_sortedToC, oldS, _sortedToC, oldS + 1, newS - oldS);
_sortedToC[oldS] = oldC;
ResyncReverseMap(oldS, newS);
}
_chrono[oldC] = _undoOldVal;
}
_oldestC = _undoOldestC;
_coreSum = _undoCoreSum;
_sumTicks = _undoSumTicks;
_undoValid = false;
}
#endregion
/// <summary>
/// Core streaming step: feed a single value, get JMA.
/// Honors isNew semantics by snapshotting state+buffers.
@@ -173,13 +446,13 @@ public sealed class Jma : AbstractBase
{
_p_state = _state;
_devBuffer.Snapshot();
_volBuffer.Snapshot();
_undoValid = false;
}
else
{
_state = _p_state;
_devBuffer.Restore();
_volBuffer.Restore();
UndoVolatility();
}
}
@@ -211,8 +484,7 @@ public sealed class Jma : AbstractBase
double volatility = _devBuffer.Average;
// 3. 128-bar volatility history + middle-65 trimmed mean
_volBuffer.Add(volatility);
double refVolatility = CalculateTrimmedMean(volatility);
double refVolatility = PushVolatility(volatility);
refVolatility = refVolatility <= 0.0 ? deviation : refVolatility;
// 4. Jurik dynamic exponent d from abs/refVolatility
@@ -324,7 +596,7 @@ public sealed class Jma : AbstractBase
// so subsequent streaming Update calls with isNew=false will use correct _p_state
_p_state = _state;
_devBuffer.Snapshot();
_volBuffer.Snapshot();
_undoValid = false;
Last = new TValue(tSpan[len - 1], vSpan[len - 1]);
return new TSeries(t, v);
@@ -390,51 +662,4 @@ public sealed class Jma : AbstractBase
TSeries results = indicator.Update(source);
return (results, indicator);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private double CalculateTrimmedMean(double fallback)
{
int count = _volBuffer.Count;
if (count < 16)
{
return fallback;
}
// Stack-allocate scratch buffer for sorting (max 128 * 8 bytes = 1KB)
// This eliminates the heap-allocated _sorted field and improves cache locality
Span<double> sorted = stackalloc double[count];
_volBuffer.CopyTo(sorted);
sorted.Sort();
int start, end;
if (count >= VolWindowSize)
{
// canonical JMA: central 65 of 128 -> indices 32..96
// Approximately removes the outer 25% on each tail
int leftSkip = (int)Math.Ceiling((VolWindowSize - JurikTrimCount) / 2.0);
start = leftSkip;
end = start + JurikTrimCount - 1;
}
else
{
// for shorter history, use central ~50% as a reasonable proxy
int slice = (int)Math.Max(5, Math.Round(count * 0.5));
int drop = (count - slice) / 2;
start = drop;
end = drop + slice - 1;
}
if (start < 0)
{
start = 0;
}
if (end >= count)
{
end = count - 1;
}
int len = end - start + 1;
return sorted.Slice(start, len).SumSIMD() / len;
}
}
+97 -38
View File
@@ -8,6 +8,11 @@ indicator("Jurik Moving Average", "JMA", overlay=true)
//@param period Number of bars used in the calculation (>= 1)
//@param phase Phase shift (-100 to 100). Negative = smoother, positive = more leading
//@returns JMA value with Jurik-style spectral volatility adaptation
//
// The 128-bar volatility distribution is held permanently sorted and mutated by one
// binary-searched remove + insert per bar, and the middle-65 trimmed mean is carried as a
// running sum updated by boundary-crossing deltas. This replaces the per-bar rebuild,
// array.sort() and 65-element summation of the naive formulation.
jma(series float source, simple int period, simple int phase = 0) =>
// ---- Precomputed length/phase parameters (constant per series) ----
simple float _PHASE = phase < -100 ? 0.5 : phase > 100 ? 2.5 : (phase * 0.01) + 1.5
@@ -19,6 +24,12 @@ jma(series float source, simple int period, simple int phase = 0) =>
simple float _SQRT_DIV = _SQRT_PARAM / (_SQRT_PARAM + 1.0)
simple float _P_EXP = math.max(_LOG_PARAM - 2.0, 0.5)
// Trimmed-mean core: middle 65 of the 128 sorted volatility samples -> ranks 32..96
simple int _CORE_LO = 32
simple int _CORE_HI = 96
simple int _CORE_CNT = 65
simple int _REFRESH = 1024 // periodic exact re-sum to bound float drift
// ---- Internal state (persists across bars) ----
var float paramA = na
var float paramB = na
@@ -34,11 +45,14 @@ jma(series float source, simple int period, simple int phase = 0) =>
var int volCount = 0
var array<float> volWindow = array.new_float(10, 0.0)
// 128-bar volatility distribution
var int distIndex = 0
// 128-bar volatility distribution, held as a permanently sorted array plus a
// chronological circular buffer that only identifies the expiring sample.
var array<float> chrono = array.new_float(128, 0.0)
var array<float> sortedArr = array.new_float(0)
var int chronoIdx = 0
var int distCount = 0
var array<float> distWindow = array.new_float(128, 0.0)
var array<float> sorted = array.new_float(0)
var float coreSum = 0.0
var int refreshTick = 0
float current_jma = na
@@ -75,44 +89,89 @@ jma(series float source, simple int period, simple int phase = 0) =>
float highD = volCount > 0 ? cycleDelta / (volCount < 10 ? volCount : 10) : dLocal
// 3) 128-bar volatility distribution + trimmed mean
array.set(distWindow, distIndex, highD)
distIndex += 1
if distIndex >= 128
distIndex := 0
float dRef = highD
if distCount < 128
// Warmup: insert in order; trim boundaries are still expanding every bar.
int wLo = 0
int wHi = distCount
while wLo < wHi
int wMid = int((wLo + wHi) / 2)
if array.get(sortedArr, wMid) > highD
wHi := wMid
else
wLo := wMid + 1
array.insert(sortedArr, wLo, highD)
array.set(chrono, chronoIdx, highD)
chronoIdx := (chronoIdx + 1) % 128
distCount += 1
float dRef = highD
if distCount >= 16
int count = distCount
array.clear(sorted)
for i = 0 to count - 1
int idx = distIndex - 1 - i
if idx < 0
idx += 128
array.push(sorted, array.get(distWindow, idx))
array.sort(sorted)
int idxLo = 0
int idxHi = 0
if count >= 128
idxLo := 32
idxHi := 96
else
int slice = int(math.max(5.0, math.round(count * 0.5)))
int drop = (count - slice) / 2
idxLo := drop
idxHi := drop + slice - 1
if idxLo < 0
idxLo := 0
if idxHi >= count
idxHi := count - 1
float sum = 0.0
if distCount == 128
float sSeed = 0.0
for i = _CORE_LO to _CORE_HI
sSeed += array.get(sortedArr, i)
coreSum := sSeed
refreshTick := 0
dRef := coreSum / float(_CORE_CNT)
else if distCount >= 16
int slice = int(math.max(5.0, math.round(distCount * 0.5)))
int drop = (distCount - slice) / 2
int idxLo = math.max(drop, 0)
int idxHi = math.min(drop + slice - 1, distCount - 1)
float sWarm = 0.0
for i = idxLo to idxHi
sum += array.get(sorted, i)
dRef := sum / float(idxHi - idxLo + 1)
sWarm += array.get(sortedArr, i)
dRef := sWarm / float(idxHi - idxLo + 1)
else
// Steady state: one delete + one insert, O(1) core-sum update.
float oldVal = array.get(chrono, chronoIdx)
// Leftmost rank holding oldVal (any equal element yields the same multiset).
int rLo = 0
int rHi = 128
while rLo < rHi
int rMid = int((rLo + rHi) / 2)
if array.get(sortedArr, rMid) < oldVal
rLo := rMid + 1
else
rHi := rMid
// Deletion delta against the current 128-element sorted array.
float dRem = 0.0
if rLo <= _CORE_HI
float displaced = rLo < _CORE_LO ? array.get(sortedArr, _CORE_LO) : oldVal
dRem := array.get(sortedArr, _CORE_HI + 1) - displaced
array.remove(sortedArr, rLo)
// Insertion rank in the 127-element post-deletion array.
int iLo = 0
int iHi = 127
while iLo < iHi
int iMid = int((iLo + iHi) / 2)
if array.get(sortedArr, iMid) > highD
iHi := iMid
else
iLo := iMid + 1
// Insertion delta against that same 127-element array.
float dIns = 0.0
if iLo <= _CORE_HI
float entering = iLo < _CORE_LO ? array.get(sortedArr, _CORE_LO - 1) : highD
dIns := entering - array.get(sortedArr, _CORE_HI)
array.insert(sortedArr, iLo, highD)
array.set(chrono, chronoIdx, highD)
chronoIdx := (chronoIdx + 1) % 128
coreSum += dRem + dIns
refreshTick += 1
if refreshTick >= _REFRESH
refreshTick := 0
float sFix = 0.0
for i = _CORE_LO to _CORE_HI
sFix += array.get(sortedArr, i)
coreSum := sFix
dRef := coreSum / float(_CORE_CNT)
if dRef <= 0.0
dRef := dLocal
-154
View File
@@ -1,154 +0,0 @@
{
"runtimeTarget": {
"name": ".NETCoreApp,Version=v10.0",
"signature": ""
},
"compilationOptions": {},
"targets": {
".NETCoreApp,Version=v10.0": {
"NDBadge/1.0.0": {
"dependencies": {
"SkiaSharp": "3.119.1",
"SkiaSharp.NativeAssets.Linux": "3.119.1"
},
"runtime": {
"NDBadge.dll": {}
}
},
"SkiaSharp/3.119.1": {
"dependencies": {
"SkiaSharp.NativeAssets.Win32": "3.119.1",
"SkiaSharp.NativeAssets.macOS": "3.119.1"
},
"runtime": {
"lib/net8.0/SkiaSharp.dll": {
"assemblyVersion": "3.119.0.0",
"fileVersion": "3.119.1.0"
}
}
},
"SkiaSharp.NativeAssets.Linux/3.119.1": {
"runtimeTargets": {
"runtimes/linux-arm/native/libSkiaSharp.so": {
"rid": "linux-arm",
"assetType": "native",
"fileVersion": "0.0.0.0"
},
"runtimes/linux-arm64/native/libSkiaSharp.so": {
"rid": "linux-arm64",
"assetType": "native",
"fileVersion": "0.0.0.0"
},
"runtimes/linux-loongarch64/native/libSkiaSharp.so": {
"rid": "linux-loongarch64",
"assetType": "native",
"fileVersion": "0.0.0.0"
},
"runtimes/linux-musl-arm/native/libSkiaSharp.so": {
"rid": "linux-musl-arm",
"assetType": "native",
"fileVersion": "0.0.0.0"
},
"runtimes/linux-musl-arm64/native/libSkiaSharp.so": {
"rid": "linux-musl-arm64",
"assetType": "native",
"fileVersion": "0.0.0.0"
},
"runtimes/linux-musl-loongarch64/native/libSkiaSharp.so": {
"rid": "linux-musl-loongarch64",
"assetType": "native",
"fileVersion": "0.0.0.0"
},
"runtimes/linux-musl-riscv64/native/libSkiaSharp.so": {
"rid": "linux-musl-riscv64",
"assetType": "native",
"fileVersion": "0.0.0.0"
},
"runtimes/linux-musl-x64/native/libSkiaSharp.so": {
"rid": "linux-musl-x64",
"assetType": "native",
"fileVersion": "0.0.0.0"
},
"runtimes/linux-riscv64/native/libSkiaSharp.so": {
"rid": "linux-riscv64",
"assetType": "native",
"fileVersion": "0.0.0.0"
},
"runtimes/linux-x64/native/libSkiaSharp.so": {
"rid": "linux-x64",
"assetType": "native",
"fileVersion": "0.0.0.0"
},
"runtimes/linux-x86/native/libSkiaSharp.so": {
"rid": "linux-x86",
"assetType": "native",
"fileVersion": "0.0.0.0"
}
}
},
"SkiaSharp.NativeAssets.macOS/3.119.1": {
"runtimeTargets": {
"runtimes/osx/native/libSkiaSharp.dylib": {
"rid": "osx",
"assetType": "native",
"fileVersion": "0.0.0.0"
}
}
},
"SkiaSharp.NativeAssets.Win32/3.119.1": {
"runtimeTargets": {
"runtimes/win-arm64/native/libSkiaSharp.dll": {
"rid": "win-arm64",
"assetType": "native",
"fileVersion": "0.0.0.0"
},
"runtimes/win-x64/native/libSkiaSharp.dll": {
"rid": "win-x64",
"assetType": "native",
"fileVersion": "0.0.0.0"
},
"runtimes/win-x86/native/libSkiaSharp.dll": {
"rid": "win-x86",
"assetType": "native",
"fileVersion": "0.0.0.0"
}
}
}
}
},
"libraries": {
"NDBadge/1.0.0": {
"type": "project",
"serviceable": false,
"sha512": ""
},
"SkiaSharp/3.119.1": {
"type": "package",
"serviceable": true,
"sha512": "sha512-+Ru1BTSZQne3Vp+vbSb50Ke3Nlc3ZnItxx4+751J9WZ8YzLKAV/n+9DAo4zFTyeCI//ueT63c+VybmTTpYBEiw==",
"path": "skiasharp/3.119.1",
"hashPath": "skiasharp.3.119.1.nupkg.sha512"
},
"SkiaSharp.NativeAssets.Linux/3.119.1": {
"type": "package",
"serviceable": true,
"sha512": "sha512-9YNoc4SeKvQhrwiqwT4ezkNfMywPdPSK+UFvo/CaoXqLixcnYOTsQKm5BF9mc4+q3vKgDtEgMt0d1ygZhJTEHg==",
"path": "skiasharp.nativeassets.linux/3.119.1",
"hashPath": "skiasharp.nativeassets.linux.3.119.1.nupkg.sha512"
},
"SkiaSharp.NativeAssets.macOS/3.119.1": {
"type": "package",
"serviceable": true,
"sha512": "sha512-6hR3BdLhApjDxR1bFrJ7/lMydPfI01s3K+3WjIXFUlfC0MFCFCwRzv+JtzIkW9bDXs7XUVQS+6EVf0uzCasnGQ==",
"path": "skiasharp.nativeassets.macos/3.119.1",
"hashPath": "skiasharp.nativeassets.macos.3.119.1.nupkg.sha512"
},
"SkiaSharp.NativeAssets.Win32/3.119.1": {
"type": "package",
"serviceable": true,
"sha512": "sha512-8C4GSXVJqSr0y3Tyyv5jz6MJSTVUyYkMjeKrzK+VyZPGLo89MNoUEclVuYahzOCDdtbfXrd2HtxXfDuvoSXrUw==",
"path": "skiasharp.nativeassets.win32/3.119.1",
"hashPath": "skiasharp.nativeassets.win32.3.119.1.nupkg.sha512"
}
}
}
Binary file not shown.
Binary file not shown.
-13
View File
@@ -1,13 +0,0 @@
{
"runtimeOptions": {
"tfm": "net10.0",
"framework": {
"name": "Microsoft.NETCore.App",
"version": "10.0.0"
},
"configProperties": {
"System.Reflection.Metadata.MetadataUpdater.IsSupported": false,
"System.Runtime.Serialization.EnableUnsafeBinaryFormatterSerialization": false
}
}
}
Binary file not shown.
-22
View File
@@ -1,22 +0,0 @@
<svg xmlns='http://www.w3.org/2000/svg'
xmlns:xlink='http://www.w3.org/1999/xlink' width='101.38281' height='20' role='img' aria-label='languages: 5'>
<title># Classes: 1181</title>
<linearGradient id='s' x2='0' y2='100%'>
<stop offset='0' stop-color='#bbb' stop-opacity='.1'/>
<stop offset='1' stop-opacity='.1'/>
</linearGradient>
<clipPath id='r'>
<rect width='101.38281' height='20' rx='3' fill='#fff'/>
</clipPath>
<g clip-path='url(#r)'>
<rect width='62.6875' height='20' fill='#555'/>
<rect x='62.6875' width='38.695312' height='20' fill='#007ec6'/>
<rect width='101.38281' height='20' fill='url(#s)'/>
</g>
<g fill='#FFF' text-anchor='center' font-family='Verdana,Geneva,DejaVu Sans,sans-serif' text-rendering='geometricPrecision' font-size='110'>
<text aria-hidden='true' x='40' y='150' fill='#010101' fill-opacity='.3' transform='scale(.1)' textLength='526.875'># Classes</text>
<text x='40' y='140' transform='scale(.1)' fill='#FFF' textLength='526.875'># Classes</text>
<text aria-hidden='true' x='666.875' y='150' fill='#010101' fill-opacity='.3' transform='scale(.1)' textLength='266.95312'>1181</text>
<text x='666.875' y='140' transform='scale(.1)' fill='#FFF' textLength='266.95312'>1181</text>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 1.3 KiB

-22
View File
@@ -1,22 +0,0 @@
<svg xmlns='http://www.w3.org/2000/svg'
xmlns:xlink='http://www.w3.org/1999/xlink' width='188.0957' height='20' role='img' aria-label='languages: 5'>
<title>Percentage of Comments: 33.07</title>
<linearGradient id='s' x2='0' y2='100%'>
<stop offset='0' stop-color='#bbb' stop-opacity='.1'/>
<stop offset='1' stop-opacity='.1'/>
</linearGradient>
<clipPath id='r'>
<rect width='188.0957' height='20' rx='3' fill='#fff'/>
</clipPath>
<g clip-path='url(#r)'>
<rect width='146.0664' height='20' fill='#555'/>
<rect x='146.0664' width='42.029297' height='20' fill='#007ec6'/>
<rect width='188.0957' height='20' fill='url(#s)'/>
</g>
<g fill='#FFF' text-anchor='center' font-family='Verdana,Geneva,DejaVu Sans,sans-serif' text-rendering='geometricPrecision' font-size='110'>
<text aria-hidden='true' x='40' y='150' fill='#010101' fill-opacity='.3' transform='scale(.1)' textLength='1360.6641'>Percentage of Comments</text>
<text x='40' y='140' transform='scale(.1)' fill='#FFF' textLength='1360.6641'>Percentage of Comments</text>
<text aria-hidden='true' x='1500.6641' y='150' fill='#010101' fill-opacity='.3' transform='scale(.1)' textLength='300.29297'>33.07</text>
<text x='1500.6641' y='140' transform='scale(.1)' fill='#FFF' textLength='300.29297'>33.07</text>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 1.4 KiB

-22
View File
@@ -1,22 +0,0 @@
<svg xmlns='http://www.w3.org/2000/svg'
xmlns:xlink='http://www.w3.org/1999/xlink' width='281.4414' height='20' role='img' aria-label='languages: 5'>
<title>Average Cyclomatic Complexity for Methods: 2.13</title>
<linearGradient id='s' x2='0' y2='100%'>
<stop offset='0' stop-color='#bbb' stop-opacity='.1'/>
<stop offset='1' stop-opacity='.1'/>
</linearGradient>
<clipPath id='r'>
<rect width='281.4414' height='20' rx='3' fill='#fff'/>
</clipPath>
<g clip-path='url(#r)'>
<rect width='246.08594' height='20' fill='#555'/>
<rect x='246.08594' width='35.35547' height='20' fill='#007ec6'/>
<rect width='281.4414' height='20' fill='url(#s)'/>
</g>
<g fill='#FFF' text-anchor='center' font-family='Verdana,Geneva,DejaVu Sans,sans-serif' text-rendering='geometricPrecision' font-size='110'>
<text aria-hidden='true' x='40' y='150' fill='#010101' fill-opacity='.3' transform='scale(.1)' textLength='2360.8594'>Average Cyclomatic Complexity for Methods</text>
<text x='40' y='140' transform='scale(.1)' fill='#FFF' textLength='2360.8594'>Average Cyclomatic Complexity for Methods</text>
<text aria-hidden='true' x='2500.8594' y='150' fill='#010101' fill-opacity='.3' transform='scale(.1)' textLength='233.55469'>2.13</text>
<text x='2500.8594' y='140' transform='scale(.1)' fill='#FFF' textLength='233.55469'>2.13</text>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 1.4 KiB

-22
View File
@@ -1,22 +0,0 @@
<svg xmlns='http://www.w3.org/2000/svg'
xmlns:xlink='http://www.w3.org/1999/xlink' width='125.39453' height='20' role='img' aria-label='languages: 5'>
<title># Source Files: 1893</title>
<linearGradient id='s' x2='0' y2='100%'>
<stop offset='0' stop-color='#bbb' stop-opacity='.1'/>
<stop offset='1' stop-opacity='.1'/>
</linearGradient>
<clipPath id='r'>
<rect width='125.39453' height='20' rx='3' fill='#fff'/>
</clipPath>
<g clip-path='url(#r)'>
<rect width='86.69922' height='20' fill='#555'/>
<rect x='86.69922' width='38.695312' height='20' fill='#007ec6'/>
<rect width='125.39453' height='20' fill='url(#s)'/>
</g>
<g fill='#FFF' text-anchor='center' font-family='Verdana,Geneva,DejaVu Sans,sans-serif' text-rendering='geometricPrecision' font-size='110'>
<text aria-hidden='true' x='40' y='150' fill='#010101' fill-opacity='.3' transform='scale(.1)' textLength='766.9922'># Source Files</text>
<text x='40' y='140' transform='scale(.1)' fill='#FFF' textLength='766.9922'># Source Files</text>
<text aria-hidden='true' x='906.9922' y='150' fill='#010101' fill-opacity='.3' transform='scale(.1)' textLength='266.95312'>1893</text>
<text x='906.9922' y='140' transform='scale(.1)' fill='#FFF' textLength='266.95312'>1893</text>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 1.3 KiB

-22
View File
@@ -1,22 +0,0 @@
<svg xmlns='http://www.w3.org/2000/svg'
xmlns:xlink='http://www.w3.org/1999/xlink' width='146.10156' height='20' role='img' aria-label='languages: 5'>
<title># Lines of Code: 152828</title>
<linearGradient id='s' x2='0' y2='100%'>
<stop offset='0' stop-color='#bbb' stop-opacity='.1'/>
<stop offset='1' stop-opacity='.1'/>
</linearGradient>
<clipPath id='r'>
<rect width='146.10156' height='20' rx='3' fill='#fff'/>
</clipPath>
<g clip-path='url(#r)'>
<rect width='94.05859' height='20' fill='#555'/>
<rect x='94.05859' width='52.04297' height='20' fill='#007ec6'/>
<rect width='146.10156' height='20' fill='url(#s)'/>
</g>
<g fill='#FFF' text-anchor='center' font-family='Verdana,Geneva,DejaVu Sans,sans-serif' text-rendering='geometricPrecision' font-size='110'>
<text aria-hidden='true' x='40' y='150' fill='#010101' fill-opacity='.3' transform='scale(.1)' textLength='840.58594'># Lines of Code</text>
<text x='40' y='140' transform='scale(.1)' fill='#FFF' textLength='840.58594'># Lines of Code</text>
<text aria-hidden='true' x='980.58594' y='150' fill='#010101' fill-opacity='.3' transform='scale(.1)' textLength='400.4297'>152828</text>
<text x='980.58594' y='140' transform='scale(.1)' fill='#FFF' textLength='400.4297'>152828</text>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 1.3 KiB

-22
View File
@@ -1,22 +0,0 @@
<svg xmlns='http://www.w3.org/2000/svg'
xmlns:xlink='http://www.w3.org/1999/xlink' width='111.40234' height='20' role='img' aria-label='languages: 5'>
<title># Methods: 15405</title>
<linearGradient id='s' x2='0' y2='100%'>
<stop offset='0' stop-color='#bbb' stop-opacity='.1'/>
<stop offset='1' stop-opacity='.1'/>
</linearGradient>
<clipPath id='r'>
<rect width='111.40234' height='20' rx='3' fill='#fff'/>
</clipPath>
<g clip-path='url(#r)'>
<rect width='66.0332' height='20' fill='#555'/>
<rect x='66.0332' width='45.36914' height='20' fill='#007ec6'/>
<rect width='111.40234' height='20' fill='url(#s)'/>
</g>
<g fill='#FFF' text-anchor='center' font-family='Verdana,Geneva,DejaVu Sans,sans-serif' text-rendering='geometricPrecision' font-size='110'>
<text aria-hidden='true' x='40' y='150' fill='#010101' fill-opacity='.3' transform='scale(.1)' textLength='560.33203'># Methods</text>
<text x='40' y='140' transform='scale(.1)' fill='#FFF' textLength='560.33203'># Methods</text>
<text aria-hidden='true' x='700.33203' y='150' fill='#010101' fill-opacity='.3' transform='scale(.1)' textLength='333.6914'>15405</text>
<text x='700.33203' y='140' transform='scale(.1)' fill='#FFF' textLength='333.6914'>15405</text>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 1.3 KiB

-22
View File
@@ -1,22 +0,0 @@
<svg xmlns='http://www.w3.org/2000/svg'
xmlns:xlink='http://www.w3.org/1999/xlink' width='127.39844' height='20' role='img' aria-label='languages: 5'>
<title># Public Types: 1222</title>
<linearGradient id='s' x2='0' y2='100%'>
<stop offset='0' stop-color='#bbb' stop-opacity='.1'/>
<stop offset='1' stop-opacity='.1'/>
</linearGradient>
<clipPath id='r'>
<rect width='127.39844' height='20' rx='3' fill='#fff'/>
</clipPath>
<g clip-path='url(#r)'>
<rect width='88.703125' height='20' fill='#555'/>
<rect x='88.703125' width='38.695312' height='20' fill='#007ec6'/>
<rect width='127.39844' height='20' fill='url(#s)'/>
</g>
<g fill='#FFF' text-anchor='center' font-family='Verdana,Geneva,DejaVu Sans,sans-serif' text-rendering='geometricPrecision' font-size='110'>
<text aria-hidden='true' x='40' y='150' fill='#010101' fill-opacity='.3' transform='scale(.1)' textLength='787.03125'># Public Types</text>
<text x='40' y='140' transform='scale(.1)' fill='#FFF' textLength='787.03125'># Public Types</text>
<text aria-hidden='true' x='927.03125' y='150' fill='#010101' fill-opacity='.3' transform='scale(.1)' textLength='266.95312'>1222</text>
<text x='927.03125' y='140' transform='scale(.1)' fill='#FFF' textLength='266.95312'>1222</text>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 1.3 KiB

-20
View File
@@ -1,20 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- NDepend coverage exclusion file -->
<RunSettings>
<DataCollectionRunSettings>
<DataCollectors>
<DataCollector friendlyName="Code Coverage">
<Configuration>
<CodeCoverage>
<Functions>
<!-- Exclude explicit interface implementations that cause NDepend mismatch warnings -->
<Exclude>
<Function>.*::System\.Collections\..*\.GetEnumerator\(\).*</Function>
</Exclude>
</Functions>
</CodeCoverage>
</Configuration>
</DataCollector>
</DataCollectors>
</DataCollectionRunSettings>
</RunSettings>
-122
View File
@@ -1,122 +0,0 @@
#!/usr/bin/env pwsh
#requires -Version 7.0
<#
.SYNOPSIS
Generates NDepend metric badges for QuanTAlib
.DESCRIPTION
Creates SVG badges for key quality metrics that reinforce QuanTAlib's
identity: scale, quality, low complexity, and comprehensive documentation.
#>
[CmdletBinding()]
param(
[Parameter(Mandatory = $false)]
[string]$NDBadgePath = "$PSScriptRoot\NDBadge.exe",
[Parameter(Mandatory = $false)]
[string]$XmlPath = ".\ndepend\NDependOut\TrendMetrics\NDependTrendData2026.xml"
)
$ErrorActionPreference = 'Stop'
# Validate prerequisites
if (-not (Test-Path $NDBadgePath)) {
Write-Error "NDBadge.exe not found at: $NDBadgePath"
exit 1
}
if (-not (Test-Path $XmlPath)) {
Write-Error "NDepend trend data XML not found at: $XmlPath"
Write-Information "Please run ndepend.ps1 first to generate analysis data"
exit 1
}
$ScriptDir = $PSScriptRoot
$OutputDir = Join-Path $ScriptDir "badges"
# Create output directory
if (-not (Test-Path $OutputDir)) {
New-Item -ItemType Directory -Path $OutputDir -Force | Out-Null
}
Write-Information "=== Generating QuanTAlib Quality Badges ==="
Write-Information "Output directory: $OutputDir`n"
# Selected badges for QuanTAlib README
Write-Information "Generating QuanTAlib badges..."
$HighValueBadges = @(
@{
Metric = "# Lines of Code"
Output = "loc.svg"
Description = "Total lines of code"
},
@{
Metric = "# Source Files"
Output = "files.svg"
Description = "Source files"
},
@{
Metric = "# Classes"
Output = "classes.svg"
Description = "Classes"
},
@{
Metric = "# Methods"
Output = "methods.svg"
Description = "Methods"
},
@{
Metric = "# Public Types"
Output = "public-api.svg"
Description = "Public API surface"
},
@{
Metric = "Percentage of Comments"
Output = "comments.svg"
Description = "Comment percentage"
},
@{
Metric = "Average Cyclomatic Complexity for Methods"
Output = "complexity.svg"
Description = "Average complexity"
}
)
foreach ($badge in $HighValueBadges) {
$outputPath = Join-Path $OutputDir $badge.Output
Write-Information " [$($badge.Output)] $($badge.Description)"
& $NDBadgePath --xml $XmlPath --metric $badge.Metric --output $outputPath
if ($LASTEXITCODE -ne 0) {
Write-Warning "Failed to generate badge: $($badge.Output)"
}
}
# Generate summary
Write-Information "`n=== Badge Generation Complete ==="
$generatedBadges = Get-ChildItem -Path $OutputDir -Filter "*.svg"
Write-Information "Generated $($generatedBadges.Count) badges in: $OutputDir"
Write-Information "`nGenerated badges:"
$HighValueBadges | ForEach-Object {
Write-Information " - $($_.Output.PadRight(20)) : $($_.Description)"
}
Write-Information "`nMarkdown snippet for README.md:"
Write-Information @"
## Quality Metrics
[![LoC](ndepend/badges/loc.svg)]()
[![Files](ndepend/badges/files.svg)]()
[![Classes](ndepend/badges/classes.svg)]()
[![Methods](ndepend/badges/methods.svg)]()
[![Public API](ndepend/badges/public-api.svg)]()
[![Comments](ndepend/badges/comments.svg)]()
[![Complexity](ndepend/badges/complexity.svg)]()
"@
Binary file not shown.
-239
View File
@@ -1,239 +0,0 @@
#!/usr/bin/env pwsh
#requires -Version 7.0
[CmdletBinding()]
param(
[Parameter(Mandatory = $false)]
[string]$NdependLicense = $env:NDEPEND_LICENSE
)
$ErrorActionPreference = 'Stop'
$ProgressPreference = 'SilentlyContinue'
# Configuration
# Determine NDepend installation path based on OS
if ($IsWindows -or $env:OS -like "Windows*") {
$NdependDll = "C:\ndepend\net10.0\NDepend.Console.MultiOS.dll"
} else {
$NdependDll = Join-Path $HOME "NDepend/net10.0/NDepend.Console.MultiOS.dll"
}
# Ensure ScriptDir is set correctly even if $PSScriptRoot is empty (e.g., dot-sourced)
$ScriptDir = if ($PSScriptRoot) { $PSScriptRoot } else { Split-Path -Parent $MyInvocation.MyCommand.Path }
$ProjectRoot = Split-Path -Parent $ScriptDir
$CoverageDir = Join-Path $ScriptDir "coverage"
$SarifDir = Join-Path $ProjectRoot ".sarif"
$SolutionFile = Join-Path $ProjectRoot "QuanTAlib.slnx"
$TestProject = Join-Path $ProjectRoot "lib/QuanTAlib.Tests.csproj"
$TestProject2 = Join-Path $ProjectRoot "quantower/Quantower.Tests.csproj"
$RunSettingsFile = Join-Path $ProjectRoot ".config/coverage.runsettings"
$NdependProject = Join-Path $ScriptDir "quantalib.ndproj"
# Validate prerequisites
if (-not (Test-Path $NdependDll)) {
Write-Error "NDepend console not found at: $NdependDll"
exit 1
}
if ([string]::IsNullOrWhiteSpace($NdependLicense)) {
Write-Warning "NDEPEND_LICENSE environment variable not set. License activation may fail."
}
if (-not (Test-Path $SolutionFile)) {
Write-Error "Solution file not found: $SolutionFile"
exit 1
}
# Helper function for section headers
function Write-Section {
param([string]$Message)
Write-Information "`n=== $Message ==="
}
# Track analysis failure
$AnalysisFailed = $false
try {
# Create .sarif directory
Write-Section "Creating .sarif directory for Roslyn analyzer output"
if (-not (Test-Path $SarifDir)) {
New-Item -ItemType Directory -Path $SarifDir -Force | Out-Null
}
Write-Information "SARIF directory: $SarifDir"
# Restore, clean, and build
Write-Section "Cleaning and building solution (generates SARIF files)"
Write-Information "Restoring packages..."
dotnet restore $SolutionFile -v q
if ($LASTEXITCODE -ne 0) { throw "Restore failed with exit code $LASTEXITCODE" }
Write-Information "Cleaning solution..."
dotnet clean $SolutionFile -v q
if ($LASTEXITCODE -ne 0) { throw "Clean failed with exit code $LASTEXITCODE" }
Write-Information "Removing old coverage data..."
if (Test-Path $CoverageDir) {
Remove-Item -Path $CoverageDir -Recurse -Force
}
Write-Information "Building solution..."
dotnet build $SolutionFile -c Debug --no-incremental
if ($LASTEXITCODE -ne 0) { throw "Build failed with exit code $LASTEXITCODE" }
# Run tests with coverage (QuanTAlib.Tests)
Write-Section "Running tests with coverage (QuanTAlib.Tests)"
dotnet test $TestProject `
-c Debug `
--no-build `
--collect:"XPlat Code Coverage" `
--settings $RunSettingsFile `
--results-directory:$CoverageDir
if ($LASTEXITCODE -ne 0) { throw "Tests failed for QuanTAlib.Tests with exit code $LASTEXITCODE" }
# Run tests with coverage (Quantower.Tests)
Write-Section "Running tests with coverage (Quantower.Tests)"
dotnet test $TestProject2 `
-c Debug `
--no-build `
--collect:"XPlat Code Coverage" `
--settings $RunSettingsFile `
--results-directory:$CoverageDir
if ($LASTEXITCODE -ne 0) { throw "Tests failed for Quantower.Tests with exit code $LASTEXITCODE" }
# Find coverage files
Write-Information "`nSearching for coverage files..."
$CoverageFiles = Get-ChildItem -Path $CoverageDir -Filter "coverage.opencover.xml" -Recurse -File |
Select-Object -ExpandProperty FullName
if (-not $CoverageFiles) {
Write-Warning "No coverage files found in $CoverageDir"
}
else {
$CoverageFiles | ForEach-Object {
Write-Information "Coverage file: $_"
}
}
# Run JetBrains InspectCode
Write-Section "Running JetBrains InspectCode"
$InspectCodeOutput = Join-Path $SarifDir "resharper.sarif.json"
$jbPath = Get-Command "jb" -ErrorAction SilentlyContinue
if ($jbPath) {
Write-Information "Running InspectCode analysis..."
jb inspectcode $SolutionFile --output=$InspectCodeOutput --format=Sarif --no-build
if ($LASTEXITCODE -ne 0) {
Write-Warning "InspectCode completed with exit code $LASTEXITCODE"
}
else {
Write-Information "InspectCode SARIF saved to: $InspectCodeOutput"
}
}
else {
Write-Warning "JetBrains CLI (jb) not found. Skipping InspectCode analysis."
Write-Information " Install with: dotnet tool install -g JetBrains.ReSharper.GlobalTools"
}
# List SARIF files
Write-Section "SARIF files generated"
$SarifFiles = Get-ChildItem -Path $SarifDir -Filter "*.json" -ErrorAction SilentlyContinue
if ($SarifFiles) {
$SarifFiles | ForEach-Object {
Write-Information " $($_.Name) ($([math]::Round($_.Length / 1KB, 2)) KB)"
}
}
else {
Write-Information "No SARIF files found"
}
# Activate NDepend license
Write-Section "Activating NDepend license"
if (-not [string]::IsNullOrWhiteSpace($NdependLicense)) {
dotnet $NdependDll --RegLic $NdependLicense
if ($LASTEXITCODE -ne 0) { Write-Warning "License activation returned exit code $LASTEXITCODE" }
}
else {
Write-Warning "Skipping license activation (no license provided)"
}
# Run NDepend analysis
Write-Section "Running NDepend analysis"
$NdependArgs = @($NdependProject)
if ($CoverageFiles) {
$NdependArgs += "/CoverageFiles"
foreach ($file in $CoverageFiles) {
$NdependArgs += $file
}
}
dotnet $NdependDll @NdependArgs
if ($LASTEXITCODE -ne 0) {
Write-Warning "NDepend analysis completed with exit code $LASTEXITCODE"
$AnalysisFailed = $true
}
}
catch {
Write-Error "Script failed: $_"
$AnalysisFailed = $true
}
finally {
# Always deactivate license
Write-Section "Deactivating NDepend license"
if (-not [string]::IsNullOrWhiteSpace($NdependLicense)) {
dotnet $NdependDll --UnregLic
if ($LASTEXITCODE -ne 0) { Write-Warning "License deactivation returned exit code $LASTEXITCODE" }
}
else {
Write-Information "Skipping license deactivation (no license provided)"
}
# Generate badges from NDepend trend data
Write-Section "Generating quality badges"
$NDBadgePath = Join-Path $ScriptDir "NDBadge.exe"
# Find the most recent trend data file
$TrendMetricsDir = Join-Path $ScriptDir "NDependOut\TrendMetrics"
$TrendXml = if (Test-Path $TrendMetricsDir) {
Get-ChildItem -Path $TrendMetricsDir -Filter "NDependTrendData*.xml" -File |
Sort-Object Name -Descending |
Select-Object -First 1 -ExpandProperty FullName
}
else { $null }
$BadgeDir = Join-Path $ScriptDir "badges"
if ((Test-Path $NDBadgePath) -and $TrendXml -and (Test-Path $TrendXml)) {
if (-not (Test-Path $BadgeDir)) {
New-Item -ItemType Directory -Path $BadgeDir -Force | Out-Null
}
$Badges = @(
@{ Metric = "# Lines of Code"; Output = "loc.svg" },
@{ Metric = "# Source Files"; Output = "files.svg" },
@{ Metric = "# Classes"; Output = "classes.svg" },
@{ Metric = "# Methods"; Output = "methods.svg" },
@{ Metric = "# Public Types"; Output = "public-api.svg" },
@{ Metric = "Percentage of Comments"; Output = "comments.svg" },
@{ Metric = "Average Cyclomatic Complexity for Methods"; Output = "complexity.svg" }
)
foreach ($badge in $Badges) {
$outputPath = Join-Path $BadgeDir $badge.Output
& $NDBadgePath --xml $TrendXml --metric $badge.Metric --output $outputPath 2>$null
if ($LASTEXITCODE -eq 0) {
Write-Information " Generated: $($badge.Output)"
}
}
Write-Information "Badges saved to: $BadgeDir"
}
else {
Write-Information "Skipping badge generation (NDBadge.exe or trend data not found)"
}
Write-Section "Done"
if ($AnalysisFailed) {
Write-Information "Note: Analysis completed with quality gate failures"
exit 1
}
}
-565
View File
@@ -1,565 +0,0 @@
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<NDepend AppName="quantalib" Platform="DotNet" FileWrittenByProductVersion="2026.1.2.9787">
<OutputDir KeepXmlFiles="True">.\NDependOut</OutputDir>
<IDEFiles>
<IDEFile FilePath="..\QuanTAlib.slnx" Filters="-test" Configuration="DEBUG|AnyCPU">
<RootDirResolvingInfo Enabled="False" Hints="Debug|bin|.bin|b|AnyCPU|x64|x86|v*.*|net*" TimeOut="10">
<RootDir>.</RootDir>
</RootDirResolvingInfo>
</IDEFile>
</IDEFiles>
<RuntimeProfileDesc>.NET 10.0</RuntimeProfileDesc>
<Assemblies />
<Dirs />
<MergeCodeGeneratedByCompiler>True</MergeCodeGeneratedByCompiler>
<CompressNDar>True</CompressNDar>
<ZipSourceFiles>True</ZipSourceFiles>
<ForceReturnZeroExitCode>False</ForceReturnZeroExitCode>
<Report Kind="0" SectionsEnabled="110591" XslPath="" DefaultTheme="dark" Flags="4455424" NbItemsToUnfold="3" NbItemsPerRule="20" MaxNbSourceFiles="2000" />
<BuildComparisonSetting ProjectMode="CurrentProject" BuildMode="NDaysAgoAnalysisResult" ProjectFileToCompareWith="" BuildFileToCompareWith="" NDaysAgo="30" />
<BaselineInUISetting ProjectMode="CurrentProject" BuildMode="NDaysAgoAnalysisResult" ProjectFileToCompareWith="" BuildFileToCompareWith="" NDaysAgo="30" />
<CoverageFiles CoverageDir="" CoverageDirFilter="" UncoverableAttribute="" CoverageExclusionFile="">
<CoverageFile>.\coverage\43fa2c87-f47e-4cfd-bc4d-2b640a2a37d6\coverage.opencover.xml</CoverageFile>
</CoverageFiles>
<TrendMetrics UseCustomLog="False" LogRecurrence="3" LogLabel="2" UseCustomDir="False" CustomDir="">
<Chart Name="Size" ShowInReport="True">
<Serie MetricName="# Lines of Code" MetricUnit="Loc" Color="#FF00BFFF" ChartType="Line" ScaleExp="0" />
<Serie MetricName="# Lines of Code Covered" MetricUnit="Loc" Color="#FF32CD32" ChartType="Area" ScaleExp="0" />
<Serie MetricName="# Lines of Code (NotMyCode)" MetricUnit="Loc" Color="#FFA9A9A9" ChartType="Area" ScaleExp="0" />
<Serie MetricName="# Lines of Comments" MetricUnit="Lines" Color="#FF008000" ChartType="Line" ScaleExp="0" />
</Chart>
<Chart Name="% Coverage and % Debt" ShowInReport="True">
<Serie MetricName="Percentage Code Coverage" MetricUnit="%" Color="#FF32CD32" ChartType="Area" ScaleExp="0" />
<Serie MetricName="Percentage Debt (Metric)" MetricUnit="%" Color="#FFFF0000" ChartType="Line" ScaleExp="0" />
</Chart>
<Chart Name="Issues" ShowInReport="True">
<Serie MetricName="# New Issues since Baseline" MetricUnit="issues" Color="#FFFF0000" ChartType="Line" ScaleExp="0" />
<Serie MetricName="# Issues Fixed since Baseline" MetricUnit="issues" Color="#FF32CD32" ChartType="Line" ScaleExp="0" />
<Serie MetricName="# Blocker/Critical/High Issues" MetricUnit="issues" Color="#FFFF8C00" ChartType="Line" ScaleExp="0" />
<Serie MetricName="# Issues" MetricUnit="issues" Color="#FFFFD700" ChartType="Line" ScaleExp="-2" />
</Chart>
<Chart Name="Rules" ShowInReport="True">
<Serie MetricName="# Rules" MetricUnit="Rules" Color="#FF66CDAA" ChartType="Line" ScaleExp="0" />
<Serie MetricName="# Rules Violated" MetricUnit="Rules" Color="#FFFF8C00" ChartType="Area" ScaleExp="0" />
<Serie MetricName="# Critical Rules Violated" MetricUnit="Rules" Color="#FFFF0000" ChartType="Area" ScaleExp="0" />
</Chart>
<Chart Name="Quality Gates" ShowInReport="True">
<Serie MetricName="# Quality Gates Fail" MetricUnit="quality gates" Color="#FFFF0000" ChartType="Line" ScaleExp="0" />
<Serie MetricName="# Quality Gates Warn" MetricUnit="quality gates" Color="#FFFF8C00" ChartType="Line" ScaleExp="0" />
<Serie MetricName="# Quality Gates" MetricUnit="quality gates" Color="#FF32CD32" ChartType="Line" ScaleExp="0" />
</Chart>
<Chart Name="Debt" ShowInReport="True">
<Serie MetricName="Debt (Metric)" MetricUnit="man-days" Color="#FFFF0000" ChartType="Line" ScaleExp="0" />
<Serie MetricName="Annual Interest (Metric)" MetricUnit="man-days" Color="#FFFF8C00" ChartType="Line" ScaleExp="0" />
</Chart>
</TrendMetrics>
<GitHub Account="" Repo="" />
<IssueImport ResolveSarifInSolutionDirectories="True" />
<HistoricAnalysisResult PersistRecurrence="3" UseCustomDir="False" CustomDir="" RetentionNDays="60" />
<SourceFileRebasing FromPath="" ToPath="" />
<PathVariables />
<RuleFiles />
<GraphFiles />
<ProjectRules AreActive="True" QueryPersistenceKind="PersistOnlyQueryIdForUntouchedQueries" />
<ProjectDebtSettings DebtSettingsStorage="0" SettingsFilePath="">
<DebtSettings>
<DebtFactor>1</DebtFactor>
<AnnualInterestFactor>1</AnnualInterestFactor>
<DebtDefault>0</DebtDefault>
<AnnualInterestDefault>0</AnnualInterestDefault>
<DebtStringFormat>$ManDay$</DebtStringFormat>
<MoneyPerManHour>50</MoneyPerManHour>
<Currency>USD</Currency>
<CurrencyLocation>After</CurrencyLocation>
<EstimatedNumberOfManDayToDevelop1000LogicalLinesOfCode>18</EstimatedNumberOfManDayToDevelop1000LogicalLinesOfCode>
<NumberOfWorkDayPerYear>240</NumberOfWorkDayPerYear>
<NumberOfWorkHourPerDay>8</NumberOfWorkHourPerDay>
<A2B_RatingThreshold>5</A2B_RatingThreshold>
<B2C_RatingThreshold>10</B2C_RatingThreshold>
<C2D_RatingThreshold>20</C2D_RatingThreshold>
<D2E_RatingThreshold>50</D2E_RatingThreshold>
<Low2Medium_SeverityThreshold>1200000000</Low2Medium_SeverityThreshold>
<Medium2High_SeverityThreshold>12000000000</Medium2High_SeverityThreshold>
<High2Critical_SeverityThreshold>72000000000</High2Critical_SeverityThreshold>
<Critical2Blocker_SeverityThreshold>360000000000</Critical2Blocker_SeverityThreshold>
</DebtSettings>
</ProjectDebtSettings><Queries>
<Group Name="Custom Rules" Active="True" ShownInReport="False">
<!-- ND1000: Avoid types too big - threshold increased to 500 for complex financial indicators -->
<Query Active="True" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="True"><![CDATA[// <Name>ND1000: Avoid types too big</Name>
warnif count > 0
from t in JustMyCode.Types
where t.NbLinesOfCode > 500 &&
!t.IsGeneratedByCompiler
let loc = t.NbLinesOfCode
orderby loc descending
select new {
t,
loc,
t.Methods,
t.Fields
}
// This rule identifies types that are too large and should be split into smaller, more focused types.
// Threshold increased from default 200 to 500 to accommodate complex financial algorithm classes.
// <Debt>10 min per issue</Debt>
]]></Query>
<!-- ND1004: Avoid methods with too many parameters - threshold increased to 8 for OHLCV data methods -->
<Query Active="True" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="True"><![CDATA[// <Name>ND1004: Avoid methods with too many parameters</Name>
warnif count > 0
from m in JustMyCode.Methods
where m.NbParameters > 8 &&
!m.IsGeneratedByCompiler
let np = m.NbParameters
orderby np descending
select new {
m,
np,
m.NbLinesOfCode
}
// This rule identifies methods with too many parameters.
// Threshold increased from default 5 to 8 to accommodate OHLCV bar data (6 values + time + flags).
// <Debt>5 min per issue</Debt>
]]></Query>
</Group>
<Group Name="Quality Gates" Active="True" ShownInReport="False">
<Query Active="True" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$Quality Gates Evolution$]]></Query>
<Query Active="True" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$Percentage Coverage$]]></Query>
<Query Active="True" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$Percentage Coverage on New Code$]]></Query>
<Query Active="True" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$Percentage Coverage on Refactored Code$]]></Query>
<Query Active="True" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$Blocker Issues$]]></Query>
<Query Active="True" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$Critical Issues$]]></Query>
<Query Active="True" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$New Blocker / Critical / High Issues$]]></Query>
<Query Active="True" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$Critical Rules Violated$]]></Query>
<Query Active="True" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$Treat Compiler Warnings as Error$]]></Query>
<Query Active="True" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$Percentage Debt$]]></Query>
<Query Active="False" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$Debt$]]></Query>
<Query Active="True" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$New Debt since Baseline$]]></Query>
<Query Active="True" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$Debt Rating per Namespace$]]></Query>
<Query Active="False" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$Annual Interest$]]></Query>
<Query Active="True" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$New Annual Interest since Baseline$]]></Query>
<Query Active="False" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$Unnecessary NDepend SuppressMessageAttribute Usage$]]></Query>
</Group>
<Group Name="Hot Spots" Active="True" ShownInReport="True">
<Query Active="True" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$Types Hot Spots$]]></Query>
<Query Active="True" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$Types to Fix Priority$]]></Query>
<Query Active="True" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$Issues to Fix Priority$]]></Query>
<Query Active="True" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$Debt and Issues per Rule$]]></Query>
<Query Active="True" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$New Debt and Issues per Rule$]]></Query>
<Query Active="True" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$Debt and Issues per Code Element$]]></Query>
<Query Active="True" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$New Debt and Issues per Code Element$]]></Query>
</Group>
<Group Name="Code Smells" Active="True" ShownInReport="False">
<Query Active="False" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="True"><![CDATA[$ND1000$]]></Query>
<Query Active="True" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$ND1001$]]></Query>
<Query Active="True" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$ND1002$]]></Query>
<Query Active="True" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$ND1003$]]></Query>
<Query Active="False" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="True"><![CDATA[$ND1004$]]></Query>
<Query Active="True" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$ND1005$]]></Query>
<Query Active="True" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$ND1006$]]></Query>
<Query Active="True" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$ND1007$]]></Query>
<Query Active="False" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$ND1008$]]></Query>
<Query Active="True" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$ND1009$]]></Query>
</Group>
<Group Name="Code Smells Regression" Active="True" ShownInReport="False">
<Query Active="True" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$ND1100$]]></Query>
<Query Active="True" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$ND1101$]]></Query>
<Query Active="True" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$ND1102$]]></Query>
<Query Active="True" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$ND1103$]]></Query>
<Query Active="True" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$ND1104$]]></Query>
<Query Active="True" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$ND1105$]]></Query>
<Query Active="True" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$ND1106$]]></Query>
<Query Active="True" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$ND1107$]]></Query>
<Query Active="True" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$ND1108$]]></Query>
</Group>
<Group Name="Object Oriented Design" Active="True" ShownInReport="True">
<Query Active="True" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$ND1200$]]></Query>
<Query Active="True" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$ND1201$]]></Query>
<Query Active="True" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$ND1202$]]></Query>
<Query Active="True" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$ND1203$]]></Query>
<Query Active="True" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$ND1204$]]></Query>
<Query Active="True" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="True"><![CDATA[$ND1205$]]></Query>
<Query Active="True" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$ND1206$]]></Query>
<Query Active="True" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$ND1207$]]></Query>
<Query Active="True" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$ND1208$]]></Query>
<Query Active="True" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$ND1209$]]></Query>
<Query Active="True" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$ND1210$]]></Query>
<Query Active="True" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$ND1211$]]></Query>
<Query Active="True" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$ND1212$]]></Query>
<Query Active="True" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$ND1213$]]></Query>
</Group>
<Group Name="Design" Active="True" ShownInReport="False">
<Query Active="True" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$ND1300$]]></Query>
<Query Active="True" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$ND1301$]]></Query>
<Query Active="True" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="True"><![CDATA[$ND1302$]]></Query>
<Query Active="True" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="True"><![CDATA[$ND1303$]]></Query>
<Query Active="True" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$ND1304$]]></Query>
<Query Active="True" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$ND1305$]]></Query>
<Query Active="True" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$ND1306$]]></Query>
<Query Active="True" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$ND1307$]]></Query>
<Query Active="True" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$ND1308$]]></Query>
<Query Active="True" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$ND1309$]]></Query>
<Query Active="True" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$ND1310$]]></Query>
<Query Active="True" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$ND1311$]]></Query>
<Query Active="True" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$ND1312$]]></Query>
<Query Active="True" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$ND1313$]]></Query>
<Query Active="False" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$ND1314$]]></Query>
</Group>
<Group Name="Architecture" Active="True" ShownInReport="False">
<Query Active="True" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="True"><![CDATA[$ND1400$]]></Query>
<Query Active="True" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$ND1401$]]></Query>
<Query Active="True" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$ND1402$]]></Query>
<Query Active="True" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$ND1403$]]></Query>
<Query Active="True" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$ND1404$]]></Query>
<Query Active="True" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$ND1405$]]></Query>
<Query Active="True" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$ND1406$]]></Query>
<Query Active="True" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$ND1407$]]></Query>
<Query Active="True" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$ND1410$]]></Query>
<Query Active="False" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$ND1408$]]></Query>
<Query Active="False" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$ND1409$]]></Query>
<Query Active="False" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$ND9900$]]></Query>
</Group>
<Group Name="API Breaking Changes" Active="True" ShownInReport="True">
<Query Active="True" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="True"><![CDATA[$ND1500$]]></Query>
<Query Active="True" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="True"><![CDATA[$ND1501$]]></Query>
<Query Active="True" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="True"><![CDATA[$ND1502$]]></Query>
<Query Active="True" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="True"><![CDATA[$ND1503$]]></Query>
<Query Active="True" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="True"><![CDATA[$ND1504$]]></Query>
<Query Active="True" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="True"><![CDATA[$ND1505$]]></Query>
<Query Active="False" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$API: New publicly visible types$]]></Query>
<Query Active="False" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$API: New publicly visible methods$]]></Query>
<Query Active="False" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$API: New publicly visible fields$]]></Query>
</Group>
<Group Name="Code Coverage" Active="True" ShownInReport="True">
<Query Active="True" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$ND1600$]]></Query>
<Query Active="True" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$ND1601$]]></Query>
<Query Active="True" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$ND1602$]]></Query>
<Query Active="True" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$ND1603$]]></Query>
<Query Active="True" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$ND1604$]]></Query>
<Query Active="True" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$ND1605$]]></Query>
<Query Active="True" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$ND1606$]]></Query>
<Query Active="True" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$ND1607$]]></Query>
<Query Active="True" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$ND1608$]]></Query>
<Query Active="True" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$ND1609$]]></Query>
<Query Active="True" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$ND1610$]]></Query>
<Query Active="False" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$Test Methods$]]></Query>
<Query Active="False" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$Methods directly called by test Methods$]]></Query>
<Query Active="False" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$Methods directly and indirectly called by test Methods$]]></Query>
</Group>
<Group Name="Dead Code" Active="True" ShownInReport="True">
<Query Active="True" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$ND1700$]]></Query>
<Query Active="True" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$ND1701$]]></Query>
<Query Active="True" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$ND1702$]]></Query>
<Query Active="True" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$ND1703$]]></Query>
</Group>
<Group Name="Security" Active="True" ShownInReport="False">
<Query Active="True" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="True"><![CDATA[$ND3120$]]></Query>
<Query Active="True" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="True"><![CDATA[$ND3121$]]></Query>
<Query Active="True" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$ND3100$]]></Query>
<Query Active="True" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$ND3101$]]></Query>
<Query Active="True" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$ND3102$]]></Query>
<Query Active="True" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$ND3103$]]></Query>
<Query Active="True" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$ND3104$]]></Query>
<Query Active="True" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$ND3105$]]></Query>
<Query Active="True" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$ND3106$]]></Query>
<Query Active="True" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$ND3107$]]></Query>
<Query Active="True" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$ND3108$]]></Query>
</Group>
<Group Name="Visibility" Active="True" ShownInReport="False">
<Query Active="True" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$ND1800$]]></Query>
<Query Active="True" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$ND1801$]]></Query>
<Query Active="True" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$ND1802$]]></Query>
<Query Active="True" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$ND1803$]]></Query>
<Query Active="True" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$ND1804$]]></Query>
<Query Active="True" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$ND1805$]]></Query>
<Query Active="True" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$ND1806$]]></Query>
<Query Active="True" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$ND1807$]]></Query>
<Query Active="True" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$ND1808$]]></Query>
<Query Active="True" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$ND1809$]]></Query>
<Query Active="True" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$ND1810$]]></Query>
<Query Active="False" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$Methods that should be declared as 'public' in C#, 'Public' in VB.NET$]]></Query>
</Group>
<Group Name="Immutability" Active="True" ShownInReport="False">
<Query Active="True" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$ND1900$]]></Query>
<Query Active="True" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="True"><![CDATA[$ND1901$]]></Query>
<Query Active="True" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$ND1902$]]></Query>
<Query Active="True" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$ND1903$]]></Query>
<Query Active="True" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$ND1914$]]></Query>
<Query Active="True" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$ND1904$]]></Query>
<Query Active="True" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$ND1905$]]></Query>
<Query Active="True" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$ND1906$]]></Query>
<Query Active="True" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$ND1907$]]></Query>
<Query Active="True" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$ND1908$]]></Query>
<Query Active="True" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$ND1909$]]></Query>
<Query Active="True" DisplayList="False" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$ND1910$]]></Query>
<Query Active="True" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$ND1911$]]></Query>
<Query Active="True" DisplayList="False" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$ND1912$]]></Query>
<Query Active="True" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$ND1913$]]></Query>
</Group>
<Group Name="Naming Conventions" Active="True" ShownInReport="False">
<Query Active="True" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$ND2000$]]></Query>
<Query Active="True" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$ND2001$]]></Query>
<Query Active="True" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="True"><![CDATA[$ND2002$]]></Query>
<Query Active="True" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$ND2003$]]></Query>
<Query Active="True" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="True"><![CDATA[$ND2004$]]></Query>
<Query Active="True" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="True"><![CDATA[$ND2005$]]></Query>
<Query Active="True" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$ND2006$]]></Query>
<Query Active="True" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$ND2007$]]></Query>
<Query Active="True" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$ND2008$]]></Query>
<Query Active="True" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$ND2009$]]></Query>
<Query Active="True" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$ND2010$]]></Query>
<Query Active="True" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$ND2011$]]></Query>
<Query Active="True" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="True"><![CDATA[$ND2012$]]></Query>
<Query Active="True" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$ND2013$]]></Query>
<Query Active="True" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$ND2014$]]></Query>
<Query Active="True" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="True"><![CDATA[$ND2015$]]></Query>
<Query Active="True" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$ND2016$]]></Query>
<Query Active="True" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$ND2017$]]></Query>
<Query Active="False" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$ND2018$]]></Query>
<Query Active="True" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$ND2019$]]></Query>
<Query Active="True" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$ND2020$]]></Query>
<Query Active="True" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$ND2021$]]></Query>
<Query Active="True" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$ND2022$]]></Query>
</Group>
<Group Name="Source Files Organization" Active="True" ShownInReport="False">
<Query Active="True" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$ND2100$]]></Query>
<Query Active="True" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$ND2101$]]></Query>
<Query Active="True" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$ND2102$]]></Query>
<Query Active="True" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$ND2103$]]></Query>
<Query Active="True" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$ND2104$]]></Query>
<Query Active="True" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$ND2105$]]></Query>
</Group>
<Group Name=".NET Framework Usage" Active="True" ShownInReport="False">
<Group Name="System" Active="True" ShownInReport="False">
<Query Active="True" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$ND2200$]]></Query>
<Query Active="False" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$ND2201$]]></Query>
<Query Active="False" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$ND2202$]]></Query>
<Query Active="True" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$ND2203$]]></Query>
<Query Active="True" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$ND2204$]]></Query>
<Query Active="True" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$ND2205$]]></Query>
<Query Active="True" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$ND2206$]]></Query>
<Query Active="True" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$ND2207$]]></Query>
<Query Active="True" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$ND2208$]]></Query>
<Query Active="True" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$ND2209$]]></Query>
<Query Active="True" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$ND2210$]]></Query>
<Query Active="True" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$ND2211$]]></Query>
</Group>
<Group Name="System.Collections" Active="True" ShownInReport="False">
<Query Active="True" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$ND2300$]]></Query>
<Query Active="True" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$ND2301$]]></Query>
<Query Active="True" DisplayList="False" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$ND2302$]]></Query>
<Query Active="True" DisplayList="False" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$ND2303$]]></Query>
</Group>
<Group Name="System.Runtime.InteropServices" Active="True" ShownInReport="False">
<Query Active="True" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$ND2400$]]></Query>
<Query Active="True" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$ND2401$]]></Query>
<Query Active="True" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$ND2402$]]></Query>
</Group>
<Group Name="System.Threading" Active="True" ShownInReport="False">
<Query Active="True" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="True"><![CDATA[$ND2500$]]></Query>
<Query Active="True" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$ND2501$]]></Query>
<Query Active="True" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="True"><![CDATA[$ND2502$]]></Query>
<Query Active="True" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="True"><![CDATA[$ND2503$]]></Query>
<Query Active="True" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="True"><![CDATA[$ND2504$]]></Query>
<Query Active="False" DisplayList="False" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$ND2505$]]></Query>
</Group>
<Group Name="System.Xml" Active="True" ShownInReport="False">
<Query Active="True" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$ND2600$]]></Query>
<Query Active="True" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$ND2601$]]></Query>
</Group>
<Group Name="System.Globalization" Active="True" ShownInReport="False">
<Query Active="True" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$ND2700$]]></Query>
</Group>
<Group Name="System.Reflection" Active="True" ShownInReport="False">
<Query Active="True" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$ND2800$]]></Query>
<Query Active="True" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$ND2801$]]></Query>
<Query Active="True" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$ND2802$]]></Query>
</Group>
<Group Name="Microsoft.Contracts" Active="True" ShownInReport="False">
<Query Active="False" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$ND2900$]]></Query>
</Group>
</Group>
<Group Name="API Usage" Active="True" ShownInReport="False">
<Group Name="Unity" Active="True" ShownInReport="False">
<Query Active="True" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$ND3200$]]></Query>
<Query Active="True" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$ND3201$]]></Query>
<Query Active="True" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$ND3202$]]></Query>
<Query Active="True" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$ND3203$]]></Query>
<Query Active="True" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$ND3204$]]></Query>
<Query Active="True" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$ND3205$]]></Query>
<Query Active="True" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$ND3206$]]></Query>
<Query Active="True" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$ND3207$]]></Query>
<Query Active="True" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$ND3208$]]></Query>
</Group>
</Group>
<Group Name="Defining JustMyCode" Active="True" ShownInReport="False">
<Query Active="True" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$ND3000$]]></Query>
<Query Active="True" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$ND3001$]]></Query>
<Query Active="True" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$ND3002$]]></Query>
<Query Active="True" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$ND3003$]]></Query>
<Query Active="True" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$ND3004$]]></Query>
<Query Active="False" DisplayList="False" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$JustMyCode code elements$]]></Query>
<Query Active="False" DisplayList="False" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$NotMyCode code elements$]]></Query>
</Group>
<Group Name="Trend Metrics" Active="True" ShownInReport="False">
<Group Name="Issues" Active="True" ShownInReport="False">
<Query Active="True" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$# New Issues since Baseline$]]></Query>
<Query Active="True" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$# Issues Fixed since Baseline$]]></Query>
<Query Active="True" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$# Issues Worsened since Baseline$]]></Query>
<Query Active="True" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$# Issues with severity Blocker$]]></Query>
<Query Active="True" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$# Issues with severity Critical$]]></Query>
<Query Active="True" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$# Issues with severity High$]]></Query>
<Query Active="True" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$# Issues with severity Medium$]]></Query>
<Query Active="True" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$# Issues with severity Low$]]></Query>
<Query Active="True" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$# Blocker/Critical/High Issues$]]></Query>
<Query Active="True" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$# Issues$]]></Query>
<Query Active="True" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$# Suppressed Issues$]]></Query>
</Group>
<Group Name="Rules" Active="True" ShownInReport="False">
<Query Active="True" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$# Rules$]]></Query>
<Query Active="True" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$# Rules Violated$]]></Query>
<Query Active="True" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$# Critical Rules Violated$]]></Query>
</Group>
<Group Name="Quality Gates" Active="True" ShownInReport="False">
<Query Active="True" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$# Quality Gates$]]></Query>
<Query Active="True" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$# Quality Gates Warn$]]></Query>
<Query Active="True" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$# Quality Gates Fail$]]></Query>
</Group>
<Group Name="Debt" Active="True" ShownInReport="False">
<Query Active="True" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$Percentage Debt (Metric)$]]></Query>
<Query Active="True" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$Debt (Metric)$]]></Query>
<Query Active="True" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$New Debt since Baseline (Metric)$]]></Query>
<Query Active="True" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$Annual Interest (Metric)$]]></Query>
<Query Active="True" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$New Annual Interest since Baseline (Metric)$]]></Query>
<Query Active="True" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$Breaking Point$]]></Query>
<Query Active="True" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$Breaking Point of Blocker / Critical / High Issues$]]></Query>
</Group>
<Group Name="Code Size" Active="True" ShownInReport="False">
<Query Active="True" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$# Lines of Code$]]></Query>
<Query Active="True" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$# Lines of Code (JustMyCode)$]]></Query>
<Query Active="True" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$# Lines of Code (NotMyCode)$]]></Query>
<Query Active="True" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$# Lines of Code Added since the Baseline$]]></Query>
<Query Active="True" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$# Source Files$]]></Query>
<Query Active="True" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$# Line Feed$]]></Query>
<Query Active="True" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$# IL Instructions$]]></Query>
<Query Active="True" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$# IL Instructions (NotMyCode)$]]></Query>
<Query Active="True" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$# Lines of Comments$]]></Query>
<Query Active="True" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$Percentage of Comments$]]></Query>
<Query Active="True" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$# Assemblies$]]></Query>
<Query Active="True" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$# Namespaces$]]></Query>
<Query Active="True" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$# Types$]]></Query>
<Query Active="True" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$# Public Types$]]></Query>
<Query Active="True" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$# Classes$]]></Query>
<Query Active="True" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$# Abstract Classes$]]></Query>
<Query Active="True" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$# Interfaces$]]></Query>
<Query Active="True" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$# Structures$]]></Query>
<Query Active="True" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$# Methods$]]></Query>
<Query Active="True" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$# Abstract Methods$]]></Query>
<Query Active="True" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$# Concrete Methods$]]></Query>
<Query Active="True" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$# Fields$]]></Query>
</Group>
<Group Name="Maximum and Average" Active="True" ShownInReport="False">
<Query Active="True" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$Max # Lines of Code for Methods (JustMyCode)$]]></Query>
<Query Active="True" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$Average # Lines of Code for Methods$]]></Query>
<Query Active="True" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$Average # Lines of Code for Methods with at least 3 Lines of Code$]]></Query>
<Query Active="True" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$Max # Lines of Code for Types (JustMyCode)$]]></Query>
<Query Active="True" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$Average # Lines of Code for Types$]]></Query>
<Query Active="True" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$Max Cyclomatic Complexity for Methods$]]></Query>
<Query Active="True" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$Average Cyclomatic Complexity for Methods$]]></Query>
<Query Active="True" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$Max IL Cyclomatic Complexity for Methods$]]></Query>
<Query Active="True" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$Average IL Cyclomatic Complexity for Methods$]]></Query>
<Query Active="True" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$Max IL Nesting Depth for Methods$]]></Query>
<Query Active="True" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$Average IL Nesting Depth for Methods$]]></Query>
<Query Active="True" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$Max # of Methods for Types$]]></Query>
<Query Active="True" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$Average # Methods for Types$]]></Query>
<Query Active="True" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$Max # of Methods for Interfaces$]]></Query>
<Query Active="True" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$Average # Methods for Interfaces$]]></Query>
</Group>
<Group Name="Coverage" Active="True" ShownInReport="False">
<Query Active="True" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$Percentage Code Coverage$]]></Query>
<Query Active="True" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$# Lines of Code Covered$]]></Query>
<Query Active="True" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$# Lines of Code Not Covered$]]></Query>
<Query Active="True" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$# Lines of Code Uncoverable$]]></Query>
<Query Active="True" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$# Lines of Code in Types 100% Covered$]]></Query>
<Query Active="True" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$# Lines of Code in Methods 100% Covered$]]></Query>
<Query Active="True" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$Max C.R.A.P Score$]]></Query>
<Query Active="True" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$Average C.R.A.P Score$]]></Query>
<Query Active="True" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$Percentage JustMyCode Coverage$]]></Query>
<Query Active="True" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$# Lines of JustMyCode Covered$]]></Query>
<Query Active="True" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$# Lines of JustMyCode Not Covered$]]></Query>
</Group>
<Group Name="Third-Party Usage" Active="True" ShownInReport="False">
<Query Active="True" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$# Third-Party Assemblies Used$]]></Query>
<Query Active="True" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$# Third-Party Namespaces Used$]]></Query>
<Query Active="True" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$# Third-Party Types Used$]]></Query>
<Query Active="True" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$# Third-Party Methods Used$]]></Query>
<Query Active="True" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$# Third-Party Fields Used$]]></Query>
<Query Active="False" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$# Third-Party Code Elements Used$]]></Query>
</Group>
</Group>
<Group Name="Code Diff Summary" Active="True" ShownInReport="True">
<Query Active="True" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$New assemblies$]]></Query>
<Query Active="True" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$Assemblies removed$]]></Query>
<Query Active="True" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$Assemblies where code was changed$]]></Query>
<Query Active="True" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$New namespaces$]]></Query>
<Query Active="True" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$Namespaces removed$]]></Query>
<Query Active="True" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$Namespaces where code was changed$]]></Query>
<Query Active="True" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$New types$]]></Query>
<Query Active="True" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$Types removed$]]></Query>
<Query Active="True" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$Types where code was changed$]]></Query>
<Query Active="True" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$Heuristic to find types moved from one namespace or assembly to another$]]></Query>
<Query Active="True" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$Types directly using one or several types changed$]]></Query>
<Query Active="True" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$Types indirectly using one or several types changed$]]></Query>
<Query Active="True" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$New methods$]]></Query>
<Query Active="True" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$Methods removed$]]></Query>
<Query Active="True" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$Methods where code was changed$]]></Query>
<Query Active="True" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$Methods directly calling one or several methods changed$]]></Query>
<Query Active="True" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$Methods indirectly calling one or several methods changed$]]></Query>
<Query Active="True" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$New fields$]]></Query>
<Query Active="True" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$Fields removed$]]></Query>
<Query Active="True" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$Third party types that were not used and that are now used$]]></Query>
<Query Active="True" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$Third party types that were used and that are not used anymore$]]></Query>
<Query Active="True" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$Third party methods that were not used and that are now used$]]></Query>
<Query Active="True" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$Third party methods that were used and that are not used anymore$]]></Query>
<Query Active="True" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$Third party fields that were not used and that are now used$]]></Query>
<Query Active="True" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$Third party fields that were used and that are not used anymore$]]></Query>
</Group>
<Group Name="Statistics" Active="False" ShownInReport="False">
<Query Active="True" DisplayList="False" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$Most used types (Rank)$]]></Query>
<Query Active="True" DisplayList="False" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$Most used methods (Rank)$]]></Query>
<Query Active="True" DisplayList="False" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$Most used assemblies (#AssembliesUsingMe)$]]></Query>
<Query Active="True" DisplayList="False" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$Most used namespaces (#NamespacesUsingMe )$]]></Query>
<Query Active="True" DisplayList="False" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$Most used types (#TypesUsingMe )$]]></Query>
<Query Active="True" DisplayList="False" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$Most used methods (#MethodsCallingMe )$]]></Query>
<Query Active="True" DisplayList="False" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$Namespaces that use many other namespaces (#NamespacesUsed )$]]></Query>
<Query Active="True" DisplayList="False" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$Types that use many other types (#TypesUsed )$]]></Query>
<Query Active="True" DisplayList="False" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$Methods that use many other methods (#MethodsCalled )$]]></Query>
<Query Active="True" DisplayList="False" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$High-level to low-level assemblies (Level)$]]></Query>
<Query Active="True" DisplayList="False" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$High-level to low-level namespaces (Level)$]]></Query>
<Query Active="True" DisplayList="False" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$High-level to low-level types (Level)$]]></Query>
<Query Active="True" DisplayList="False" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$High-level to low-level methods (Level)$]]></Query>
</Group>
<Group Name="Samples of Custom rules" Active="False" ShownInReport="False">
<Group Name="Check Architecture" Active="False" ShownInReport="False">
<Query Active="False" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$ND9901$]]></Query>
<Query Active="False" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$ND9902$]]></Query>
<Query Active="False" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$ND9903$]]></Query>
<Query Active="False" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$ND9904$]]></Query>
<Query Active="False" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$ND9905$]]></Query>
<Query Active="False" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$ND9906$]]></Query>
<Query Active="False" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$ND9907$]]></Query>
<Query Active="False" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$ND9908$]]></Query>
<Query Active="False" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$ND9909$]]></Query>
<Query Active="False" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$ND9910$]]></Query>
</Group>
<Group Name="Check Coverage on particular Code Elements" Active="False" ShownInReport="False">
<Query Active="False" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$ND9911$]]></Query>
<Query Active="False" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$ND9912$]]></Query>
<Query Active="False" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$ND9913$]]></Query>
<Query Active="False" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$ND9914$]]></Query>
</Group>
<Group Name="Custom Naming Conventions" Active="False" ShownInReport="False">
<Query Active="False" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$ND9915$]]></Query>
<Query Active="False" DisplayList="True" DisplayStat="False" DisplaySelectionView="False" IsCriticalRule="False"><![CDATA[$ND9916$]]></Query>
</Group>
</Group>
</Queries></NDepend>
-1249
View File
File diff suppressed because it is too large Load Diff
+4
View File
@@ -25,6 +25,7 @@ from . import ( # noqa: F401
cycles,
dynamics,
errors,
feeds,
filters,
momentum,
numerics,
@@ -36,6 +37,7 @@ from . import ( # noqa: F401
volatility,
volume,
)
from .feeds import * # noqa: F401, F403 — re-export gbm() at top level
from ._compat import ALIASES, get_compat
from ._bridge import (
@@ -54,6 +56,8 @@ __all__ = [
"cycles",
"dynamics",
"errors",
"feeds",
"gbm",
"filters",
"momentum",
"numerics",
+93
View File
@@ -0,0 +1,93 @@
"""quantalib.feeds — synthetic market data generators.
Vectorized NumPy port of the C# `GBM` feed (lib/feeds/gbm/gbm.cs). No native
FFI call is involved: the entire bar sequence is generated with array
operations (cumsum / exp / rng draws), so there is no per-bar Python-loop
overhead — the same trade that makes the .NET Batch paths fast.
"""
from __future__ import annotations
import numpy as np
from numpy.typing import NDArray
__all__ = ["gbm"]
# 252 trading days * 6.5 trading hours/day * 60 minutes/hour
_MINUTES_PER_YEAR = 252.0 * 6.5 * 60.0
def gbm(
n: int,
start_price: float = 100.0,
mu: float = 0.05,
sigma: float = 0.2,
timeframe_minutes: float = 1.0,
seed: int | None = None,
) -> dict[str, NDArray[np.float64]]:
"""Generate `n` synthetic OHLCV bars via Geometric Brownian Motion.
Mirrors the drift/volatility scaling and OHLC construction of the C#
`GBM` feed, but computes the whole series in one vectorized pass instead
of bar-by-bar `Next()` calls.
Args:
n: Number of bars to generate. Must be positive.
start_price: Initial price (must be positive and finite).
mu: Annual drift/return rate.
sigma: Annual volatility (must be non-negative and finite).
timeframe_minutes: Bar duration in minutes (must be positive).
seed: Optional random seed for reproducibility.
Returns:
dict with keys "open", "high", "low", "close", "volume", each a
float64 NumPy array of length `n`.
"""
if n <= 0:
raise ValueError("n must be positive")
if start_price <= 0 or not np.isfinite(start_price):
raise ValueError("start_price must be positive and finite")
if not np.isfinite(mu):
raise ValueError("mu must be finite")
if sigma < 0 or not np.isfinite(sigma):
raise ValueError("sigma must be non-negative and finite")
if timeframe_minutes <= 0:
raise ValueError("timeframe_minutes must be positive")
rng = np.random.default_rng(seed)
dt = timeframe_minutes / _MINUTES_PER_YEAR
drift = (mu - 0.5 * sigma * sigma) * dt
vol = sigma * np.sqrt(dt)
log_returns = drift + vol * rng.standard_normal(n)
close = start_price * np.exp(np.cumsum(log_returns))
# Fall back to the previous price on any non-finite/non-positive draw,
# matching the C# guard in GBM.Next(). Rare, so a short scalar pass is fine.
bad = ~np.isfinite(close) | (close <= 0)
if bad.any():
last = start_price
for i in range(n):
if bad[i]:
close[i] = last
last = close[i]
open_ = np.empty(n, dtype=np.float64)
open_[0] = start_price
open_[1:] = close[:-1]
hi_base = np.maximum(open_, close)
lo_base = np.minimum(open_, close)
high = np.maximum(hi_base * (1.0 + rng.random(n) * 0.01), hi_base)
low = np.maximum(np.minimum(lo_base * (1.0 - rng.random(n) * 0.01), lo_base), np.finfo(np.float64).tiny)
volume = 1000.0 + rng.random(n) * 1000.0
return {
"open": open_,
"high": high,
"low": low,
"close": close,
"volume": volume,
}