snapkitty
developer-tools
python
market-scope / packages /prolog-rules /correlation.pl
SNAPKITTYWEST's picture
push from SNAPKITTYWEST/market-scope
8f5564f verified
Raw History Blame Contribute Delete
4.77 kB
% ═══════════════════════════════════════════════════════════════════════════════
% MARKETSCOPE β€” Correlation Breakdown Detection (Deterministic)
%
% Detects when historically correlated assets diverge.
% Outputs scenario bands, not predictions.
%
% Training_Gate: Human_Review_Required
% Audit_Spec: 4b565498-9afc-4782-af4a-c6b11a5d0058
% ═══════════════════════════════════════════════════════════════════════════════
:- module(correlation, [
correlation_breakdown/3,
check_all_pairs/2,
pair_status/3
]).
:- use_module(library(http/json)).
% ── Correlation Breakdown Detection ───────────────────────────────────────────
%% correlation_breakdown(+AssetA, +AssetB, -Window)
% Detects when rolling correlation drops below threshold.
% Window is the lookback period in days.
correlation_breakdown(AssetA, AssetB, Window) :-
rolling_corr(AssetA, AssetB, Window, Corr),
historical_avg_corr(AssetA, AssetB, Avg),
Corr < 0.3,
Avg > 0.7.
%% correlation_breakdown(+AssetA, +AssetB, -Window, -Details)
% Extended version with detailed breakdown information.
correlation_breakdown(AssetA, AssetB, Window, Details) :-
rolling_corr(AssetA, AssetB, Window, CurrentCorr),
historical_avg_corr(AssetA, AssetB, HistoricalAvg),
deviation(Deviation, CurrentCorr, HistoricalAvg),
( CurrentCorr < 0.3,
HistoricalAvg > 0.7
-> Details = _{
asset_a: AssetA,
asset_b: AssetB,
window_days: Window,
current_corr: CurrentCorr,
historical_avg: HistoricalAvg,
deviation: Deviation,
alert: true,
message: 'CORRELATION BREAKDOWN DETECTED'
}
; Details = _{
asset_a: AssetA,
asset_b: AssetB,
window_days: Window,
current_corr: CurrentCorr,
historical_avg: HistoricalAvg,
deviation: Deviation,
alert: false,
message: 'Correlation within normal range'
}
).
% ── Multi-Pair Analysis ──────────────────────────────────────────────────────
%% check_all_pairs(+Pairs, -Alerts)
% Checks all asset pairs for correlation breakdowns.
check_all_pairs(Pairs, Alerts) :-
maplist(check_pair, Pairs, Results),
include(has_alert, Results, Alerts).
%% check_pair(+Pair, -Result)
% Checks a single pair.
check_pair(AssetA-AssetB, Result) :-
( correlation_breakdown(AssetA, AssetB, 20, Details)
-> Result = Details
; Result = _{
asset_a: AssetA,
asset_b: AssetB,
alert: false,
message: 'No breakdown detected'
}
).
%% pair_status(+AssetA, +AssetB, -Status)
% Returns current correlation status.
pair_status(AssetA, AssetB, Status) :-
rolling_corr(AssetA, AssetB, 20, Current),
historical_avg_corr(AssetA, AssetB, Historical),
( Current < 0.3, Historical > 0.7
-> Status = breakdown
; Current < 0.5
-> Status = weakening
; Status = normal
).
% ── Helpers ───────────────────────────────────────────────────────────────────
%% deviation(-Deviation, +Current, +Historical)
% Computes absolute deviation.
deviation(D, Current, Historical) :-
D is abs(Current - Historical).
%% has_alert(+Details)
% Checks if a result contains an alert.
has_alert(Details) :-
get_dict(alert, Details, true).
% ── Data Sources (Stubs β€” replaced at runtime) ───────────────────────────────
:- dynamic rolling_corr/4, historical_avg_corr/3.
%% set_rolling_corr(+AssetA, +AssetB, +Window, +Corr)
set_rolling_corr(AssetA, AssetB, Window, Corr) :-
retractall(rolling_corr(AssetA, AssetB, Window, _)),
assert(rolling_corr(AssetA, AssetB, Window, Corr)).
%% set_historical_avg(+AssetA, +AssetB, +Avg)
set_historical_avg(AssetA, AssetB, Avg) :-
retractall(historical_avg_corr(AssetA, AssetB, _)),
assert(historical_avg_corr(AssetA, AssetB, Avg)).