curl --request POST \
--url https://zcjbtpxuhdekpwcxmepn.supabase.co/rest/v1/rpc/portfolio_movement \
--header 'Content-Type: application/json' \
--header 'apikey: <api-key>' \
--data '
{
"p_cnpjs": [
"<string>"
],
"p_month": null
}
'import requests
url = "https://zcjbtpxuhdekpwcxmepn.supabase.co/rest/v1/rpc/portfolio_movement"
payload = {
"p_cnpjs": ["<string>"],
"p_month": None
}
headers = {
"apikey": "<api-key>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {apikey: '<api-key>', 'Content-Type': 'application/json'},
body: JSON.stringify({p_cnpjs: ['<string>'], p_month: null})
};
fetch('https://zcjbtpxuhdekpwcxmepn.supabase.co/rest/v1/rpc/portfolio_movement', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://zcjbtpxuhdekpwcxmepn.supabase.co/rest/v1/rpc/portfolio_movement",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'p_cnpjs' => [
'<string>'
],
'p_month' => null
]),
CURLOPT_HTTPHEADER => [
"Content-Type: application/json",
"apikey: <api-key>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://zcjbtpxuhdekpwcxmepn.supabase.co/rest/v1/rpc/portfolio_movement"
payload := strings.NewReader("{\n \"p_cnpjs\": [\n \"<string>\"\n ],\n \"p_month\": null\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("apikey", "<api-key>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://zcjbtpxuhdekpwcxmepn.supabase.co/rest/v1/rpc/portfolio_movement")
.header("apikey", "<api-key>")
.header("Content-Type", "application/json")
.body("{\n \"p_cnpjs\": [\n \"<string>\"\n ],\n \"p_month\": null\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://zcjbtpxuhdekpwcxmepn.supabase.co/rest/v1/rpc/portfolio_movement")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["apikey"] = '<api-key>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"p_cnpjs\": [\n \"<string>\"\n ],\n \"p_month\": null\n}"
response = http.request(request)
puts response.read_body[
{
"cnpj": "<string>",
"fund_name": "<string>",
"month": "2023-12-25",
"class": "<string>",
"subclass": "<string>",
"class_as_filed": "<string>",
"class_as_of": "2023-12-25",
"n_peers": 123,
"own_value_pct": 123,
"class_mean_pct": 123,
"class_sd_pct": 123,
"class_p01_pct": 123,
"class_p99_pct": 123,
"z": 123,
"level": "<string>",
"investigator_trigger": true,
"min_peers": 123,
"reason": "<string>"
}
]{
"code": "22023",
"message": "<string>",
"details": "<string>",
"hint": "<string>"
}{
"code": "22023",
"message": "<string>",
"details": "<string>",
"hint": "<string>"
}{
"code": "22023",
"message": "<string>",
"details": "<string>",
"hint": "<string>"
}portfolio_movement
Is a fund’s month unusual for its own class (movimento incomum). Per CNPJ, for one month (p_month, or the last complete FI month): the fund’s monthly QUOTA RETURN, own_value_pct = (month-end vl_quota / previous month’s - 1) x 100 from fact_fund_monthly (the one stable quota subclass; a NAV change is not used), set against the same return over every FI fund of its ANBIMA class AS FILED in the CVM Extrato (class_as_filed, the newest Extrato filing, not the class on the month’s date; class and subclass split that label at its first ’ - ’ for display). class_mean_pct and class_sd_pct are the mean and sample standard deviation of the peers’ returns winsorized at the class’s own 1st and 99th percentile that month (class_p01_pct, class_p99_pct); the fund’s own value is not winsorized. z = (own - mean) / sd. level: forte when |z| > 3 (investigator_trigger TRUE), atencao when |z| > 2, normal otherwise (strictly greater: exactly 2 is normal); nao_avaliado with a Portuguese reason when the class has fewer than min_peers (30) peers with a return, its standard deviation is 0, the fund has no class (outside the Extrato, or no classe_anbima), no return (no quota in both months, a quota subclass change), is an ETF, FIDC, FII, FIP or FIAGRO, or the month is not complete; never skipped and never a zero. No fallback to a wider class. Measured on production 2026-10-03 over monthly FI funds in classes of 30 or more: |z| > 2 flags 5.2% to 5.7% of fund-months and |z| > 3 2.4% to 2.9% over six months from 2025-12 to 2026-09 (5.6% and 2.7% in 2026-09). It states a number, a class, a sample size and a month: not a forecast, a verdict or a recommendation. One row per distinct CNPJ; more than 200 CNPJs RAISES 22023.
Row cap. A window producing more than 1000 rows raises SQLSTATE 22023 naming this function. Nothing is trimmed to fit — PostgREST would silently cut the response at 1000 and a cut-short series is indistinguishable from one that simply ends. This function does not page — narrow the window instead.
curl --request POST \
--url https://zcjbtpxuhdekpwcxmepn.supabase.co/rest/v1/rpc/portfolio_movement \
--header 'Content-Type: application/json' \
--header 'apikey: <api-key>' \
--data '
{
"p_cnpjs": [
"<string>"
],
"p_month": null
}
'import requests
url = "https://zcjbtpxuhdekpwcxmepn.supabase.co/rest/v1/rpc/portfolio_movement"
payload = {
"p_cnpjs": ["<string>"],
"p_month": None
}
headers = {
"apikey": "<api-key>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {apikey: '<api-key>', 'Content-Type': 'application/json'},
body: JSON.stringify({p_cnpjs: ['<string>'], p_month: null})
};
fetch('https://zcjbtpxuhdekpwcxmepn.supabase.co/rest/v1/rpc/portfolio_movement', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://zcjbtpxuhdekpwcxmepn.supabase.co/rest/v1/rpc/portfolio_movement",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'p_cnpjs' => [
'<string>'
],
'p_month' => null
]),
CURLOPT_HTTPHEADER => [
"Content-Type: application/json",
"apikey: <api-key>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://zcjbtpxuhdekpwcxmepn.supabase.co/rest/v1/rpc/portfolio_movement"
payload := strings.NewReader("{\n \"p_cnpjs\": [\n \"<string>\"\n ],\n \"p_month\": null\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("apikey", "<api-key>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://zcjbtpxuhdekpwcxmepn.supabase.co/rest/v1/rpc/portfolio_movement")
.header("apikey", "<api-key>")
.header("Content-Type", "application/json")
.body("{\n \"p_cnpjs\": [\n \"<string>\"\n ],\n \"p_month\": null\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://zcjbtpxuhdekpwcxmepn.supabase.co/rest/v1/rpc/portfolio_movement")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["apikey"] = '<api-key>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"p_cnpjs\": [\n \"<string>\"\n ],\n \"p_month\": null\n}"
response = http.request(request)
puts response.read_body[
{
"cnpj": "<string>",
"fund_name": "<string>",
"month": "2023-12-25",
"class": "<string>",
"subclass": "<string>",
"class_as_filed": "<string>",
"class_as_of": "2023-12-25",
"n_peers": 123,
"own_value_pct": 123,
"class_mean_pct": 123,
"class_sd_pct": 123,
"class_p01_pct": 123,
"class_p99_pct": 123,
"z": 123,
"level": "<string>",
"investigator_trigger": true,
"min_peers": 123,
"reason": "<string>"
}
]{
"code": "22023",
"message": "<string>",
"details": "<string>",
"hint": "<string>"
}{
"code": "22023",
"message": "<string>",
"details": "<string>",
"hint": "<string>"
}{
"code": "22023",
"message": "<string>",
"details": "<string>",
"hint": "<string>"
}Authorizations
The publishable key (sb_publishable_…), on every request. It is NOT a JWT — sending it as Authorization: Bearer is rejected as an invalid JWT. It identifies the project, not you, and maps to the Postgres anon role.
Body
Response
The result set, oldest first. An unknown id is an empty array, not a 404 and never a guessed value.
Was this page helpful?