vortexa-claude-skills 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +28 -0
- package/VERSION +1 -0
- package/bin/.gitkeep +0 -0
- package/bin/setup.js +302 -0
- package/commands/vortexa/_check-setup.md +9 -0
- package/commands/vortexa/_skill-template.md +100 -0
- package/commands/vortexa/breakdown.md +294 -0
- package/commands/vortexa/cargo-flows.md +247 -0
- package/commands/vortexa/compare.md +315 -0
- package/commands/vortexa/custom.md +214 -0
- package/commands/vortexa/explain.md +124 -0
- package/commands/vortexa/init.md +133 -0
- package/commands/vortexa/oow.md +189 -0
- package/commands/vortexa/seasonal.md +185 -0
- package/commands/vortexa/voyages.md +285 -0
- package/context/.gitkeep +0 -0
- package/context/cargo-movements.md +738 -0
- package/context/date-units.md +188 -0
- package/context/endpoint-template.md +176 -0
- package/context/entity-resolution.md +217 -0
- package/context/guardrails.md +161 -0
- package/context/reference-endpoints.md +651 -0
- package/context/voyages.md +636 -0
- package/lib/__init__.py +4 -0
- package/lib/aliases.json +52 -0
- package/lib/api.py +20 -0
- package/lib/entities.py +254 -0
- package/lib/inventory.py +140 -0
- package/lib/movements.py +242 -0
- package/lib/requirements.txt +6 -0
- package/lib/seasonal.py +200 -0
- package/lib/timeseries.py +271 -0
- package/lib/utils.py +120 -0
- package/lib/vessels.py +192 -0
- package/lib/visualization.py +164 -0
- package/lib/voyages.py +236 -0
- package/package.json +28 -0
- package/templates/.env.template +3 -0
|
@@ -0,0 +1,738 @@
|
|
|
1
|
+
# Cargo Movements & CargoTimeSeries
|
|
2
|
+
|
|
3
|
+
> Endpoint documentation for querying cargo flows, timeseries, and individual movements.
|
|
4
|
+
> For date/unit rules, see `date-units.md` (pre-loaded). For common error patterns, see `guardrails.md` (pre-loaded).
|
|
5
|
+
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## When to Use This Endpoint
|
|
9
|
+
|
|
10
|
+
**NEVER** use CargoMovements search to answer volume/flow questions -- it returns individual records that must be summed manually. CargoTimeSeries pre-aggregates and handles splits/double-counting correctly.
|
|
11
|
+
|
|
12
|
+
**ALWAYS** use CargoTimeSeries for aggregate volume questions and CargoMovements search for individual cargo details.
|
|
13
|
+
|
|
14
|
+
| User Wants | Endpoint | Signal Words |
|
|
15
|
+
|---|---|---|
|
|
16
|
+
| Aggregate volumes, flows, trends | CargoTimeSeries | "how much", "total", "trend", "monthly", "weekly", "barrels per day", "chart" |
|
|
17
|
+
| Breakdown by dimension | CargoTimeSeries + `timeseries_property` | "by origin", "by product", "by vessel class", "breakdown" |
|
|
18
|
+
| Individual cargo records | CargoMovements search | "list cargoes", "which shipments", "specific vessel", "cargo details", "show me the movements" |
|
|
19
|
+
| Single cargo lookup | CargoMovements record | "cargo ID", "look up this movement" |
|
|
20
|
+
|
|
21
|
+
---
|
|
22
|
+
|
|
23
|
+
## CRITICAL: Activity Filter Rules
|
|
24
|
+
|
|
25
|
+
**NEVER** use `loading_state` when the user says "exports" -- this is the #1 most common mistake.
|
|
26
|
+
**NEVER** use `unloading_state` when the user says "imports".
|
|
27
|
+
**NEVER** use `oil_on_water_state` -- it is DEPRECATED. Always use `cargo_on_water_state`.
|
|
28
|
+
**ALWAYS** set `intra_movements="exclude_intra_country"` for exports/imports queries.
|
|
29
|
+
**ALWAYS** set `filter_activity` explicitly -- never rely on the default (`any_activity`).
|
|
30
|
+
|
|
31
|
+
### Activity Selection Table
|
|
32
|
+
|
|
33
|
+
| User Says | CORRECT filter_activity | WRONG Choice | Why Wrong |
|
|
34
|
+
|---|---|---|---|
|
|
35
|
+
| "exports", "shipped out", "departures" | `loading_end` | `loading_state` | `loading_state` = currently loading at berth, not departed. Volumes will be far too low. |
|
|
36
|
+
| "imports", "arrivals", "received" | `unloading_start` | `unloading_state` | `unloading_state` = currently discharging, not arrived. Misses completed discharges. |
|
|
37
|
+
| "loadings", "loading at port" | `loading_state` | `loading_end` | `loading_end` = already departed, not actively loading. |
|
|
38
|
+
| "discharged" | `unloading_state` | `unloading_start` | `unloading_start` = arrived, not yet discharged. |
|
|
39
|
+
| "on the water", "afloat", "in transit" | `cargo_on_water_state` | `oil_on_water_state` | `oil_on_water_state` is DEPRECATED. |
|
|
40
|
+
| "floating storage", "stored at sea" | `storing_state` | `cargo_on_water_state` | `cargo_on_water_state` includes all transit, not just storage. |
|
|
41
|
+
| "everything", "all activity" | `any_activity` | omitting the parameter | Omitting defaults to `any_activity` but should always be explicit. |
|
|
42
|
+
|
|
43
|
+
### Activity + Geography Logic
|
|
44
|
+
|
|
45
|
+
**CRITICAL:** "exports" vs "imports" determines both the activity filter AND which geography filter to use.
|
|
46
|
+
|
|
47
|
+
| Query Pattern | filter_activity | Geography Filter | intra_movements |
|
|
48
|
+
|---|---|---|---|
|
|
49
|
+
| "Saudi exports" | `loading_end` | `filter_origins=[saudi_id]` | `exclude_intra_country` |
|
|
50
|
+
| "China imports" | `unloading_start` | `filter_destinations=[china_id]` | `exclude_intra_country` |
|
|
51
|
+
| "Saudi exports to China" | `loading_end` | `filter_origins=[saudi_id]` + `filter_destinations=[china_id]` | `exclude_intra_country` |
|
|
52
|
+
| "crude on the water" | `cargo_on_water_state` | (none or `filter_storage_locations`) | `all` |
|
|
53
|
+
| "floating storage in MEG" | `storing_state` | `filter_storage_locations=[meg_id]` | `all` |
|
|
54
|
+
|
|
55
|
+
### timeseries_activity vs filter_activity
|
|
56
|
+
|
|
57
|
+
These are two distinct parameters that serve different purposes:
|
|
58
|
+
|
|
59
|
+
| Parameter | Purpose | Default |
|
|
60
|
+
|---|---|---|
|
|
61
|
+
| `filter_activity` | **WHICH** cargoes to include -- filters the dataset to only cargoes in this state during the time window | Required (defaults to `any_activity`) |
|
|
62
|
+
| `timeseries_activity` | **WHEN** to count each cargo -- determines which timestamp to aggregate on | Same as `filter_activity` |
|
|
63
|
+
|
|
64
|
+
**When they match (99% of cases):** Filter on loadings, count at loading time. Filter on exports, count at export time.
|
|
65
|
+
|
|
66
|
+
**When they differ (advanced):** Filter cargoes that *loaded* in 2025, but aggregate by their *unloading* dates to see when those specific cargoes arrived:
|
|
67
|
+
- `filter_activity="loading_end"` + `filter_time_min/max` = 2025
|
|
68
|
+
- `timeseries_activity="unloading_start"` = plot arrival dates of those cargoes
|
|
69
|
+
|
|
70
|
+
**ALWAYS** set both explicitly when they should differ. If only `filter_activity` is set, `timeseries_activity` defaults to match it.
|
|
71
|
+
|
|
72
|
+
---
|
|
73
|
+
|
|
74
|
+
## Natural Language to API Mapping
|
|
75
|
+
|
|
76
|
+
### Vocabulary Reference: Activity / State
|
|
77
|
+
|
|
78
|
+
See the Activity Selection Table above for the complete mapping.
|
|
79
|
+
|
|
80
|
+
### Vocabulary Reference: Products
|
|
81
|
+
|
|
82
|
+
| User Says | Product Level | Vortexa Label |
|
|
83
|
+
|---|---|---|
|
|
84
|
+
| "crude", "crude oil" | group | Crude & Condensates |
|
|
85
|
+
| "condensate" | group_product | Condensate |
|
|
86
|
+
| "clean products", "CPP" | group | Clean Petroleum Products |
|
|
87
|
+
| "dirty products", "DPP" | group | Dirty Petroleum Products |
|
|
88
|
+
| "fuel oil", "HSFO", "VLSFO", "bunkers" | group_product | Fuel Oil |
|
|
89
|
+
| "naphtha" | group_product | Naphtha |
|
|
90
|
+
| "gasoline", "mogas", "motor gasoline" | group_product | Gasoline / Mogas |
|
|
91
|
+
| "jet fuel", "jet", "kerosene" | group_product | Jet/Kero |
|
|
92
|
+
| "gasoil", "diesel", "AGO" | group_product | Gasoil/Diesel |
|
|
93
|
+
| "LPG" | group | LPG |
|
|
94
|
+
| "LNG", "natural gas" (shipping context) | group | LNG |
|
|
95
|
+
| "VGO" | group_product | VGO |
|
|
96
|
+
|
|
97
|
+
### Vocabulary Reference: Geography
|
|
98
|
+
|
|
99
|
+
| User Says | Vortexa Geography | Layer |
|
|
100
|
+
|---|---|---|
|
|
101
|
+
| "Middle East", "MEG", "AG", "Arabian Gulf", "Persian Gulf" | Middle East/North Africa or Arabian/Persian Gulf | region or shipping_region_v2 |
|
|
102
|
+
| "USG", "US Gulf", "Gulf Coast" | US Gulf Coast | shipping_region_v2 |
|
|
103
|
+
| "PADD I", "East Coast" (US) | US Atlantic Coast | shipping_region_v2 |
|
|
104
|
+
| "ARA", "Amsterdam-Rotterdam-Antwerp" | Specific ports (Amsterdam, Rotterdam, Antwerp) | port |
|
|
105
|
+
| "WAF", "West Africa" | West Africa | shipping_region_v2 |
|
|
106
|
+
| "Med", "Mediterranean" | Mediterranean | shipping_region_v2 |
|
|
107
|
+
| "NEA", "Northeast Asia" | Northeast Asia | shipping_region_v2 |
|
|
108
|
+
| "SEA", "Southeast Asia" | Southeast Asia | shipping_region_v2 |
|
|
109
|
+
|
|
110
|
+
### Vocabulary Reference: Vessel Classes
|
|
111
|
+
|
|
112
|
+
| User Says | API Value |
|
|
113
|
+
|---|---|
|
|
114
|
+
| "VLCC", "supertanker" | `oil_vlcc` |
|
|
115
|
+
| "Suezmax" | `oil_suezmax` or `oil_suezmax_lr3` |
|
|
116
|
+
| "Aframax", "LR2" (same vessel size) | `oil_aframax` or `oil_aframax_lr2` |
|
|
117
|
+
| "Panamax", "LR1" | `oil_panamax` or `oil_panamax_lr1` |
|
|
118
|
+
| "MR", "MR2", "medium range" | `oil_mr2` or `oil_handymax_mr2` |
|
|
119
|
+
| "Handysize", "MR1" | `oil_handysize` or `oil_handysize_mr1` |
|
|
120
|
+
| "all oil tankers" | `oil` |
|
|
121
|
+
| "VLGC" | `lpg_vlgc` or `lpg_vlgc_vlec` |
|
|
122
|
+
| "LGC" | `lpg_lgc` |
|
|
123
|
+
| "MGC" | `lpg_mgc` |
|
|
124
|
+
| "all LPG carriers" | `lpg` |
|
|
125
|
+
| "Q-Max" | `lng_q_max` |
|
|
126
|
+
| "Q-Flex" | `lng_q_flex` |
|
|
127
|
+
| "Q-fleet" | `lng_q_fleet` |
|
|
128
|
+
| "two-stroke LNG" | `lng_two_stroke` |
|
|
129
|
+
| "TFDE", "DFDE" | `lng_tfde_dfde` |
|
|
130
|
+
| "steam turbine LNG" | `lng_steam` |
|
|
131
|
+
| "conventional LNG" | `lng_conventional_lng` |
|
|
132
|
+
| "all LNG carriers" | `lng` |
|
|
133
|
+
|
|
134
|
+
### Vocabulary Reference: Units and Frequency
|
|
135
|
+
|
|
136
|
+
See `date-units.md` for the complete unit defaults, frequency selection, and date parsing reference.
|
|
137
|
+
|
|
138
|
+
**Quick defaults when user does not specify:**
|
|
139
|
+
- Oil questions: `bpd` (barrels per day)
|
|
140
|
+
- LNG questions: `t` (tonnes)
|
|
141
|
+
- LPG questions: `t` (tonnes)
|
|
142
|
+
- Counting questions: `c` (count)
|
|
143
|
+
|
|
144
|
+
### Vocabulary Reference: Time Ranges
|
|
145
|
+
|
|
146
|
+
See `date-units.md` for the complete date parsing convention (calendar vs trailing periods).
|
|
147
|
+
|
|
148
|
+
**CRITICAL:** Always specify `filter_time_max` with hour, minute, and second components (e.g., `datetime(2025, 12, 31, 23, 59, 59)`) to ensure the final day's data is included. Without the time component, `datetime(2025, 12, 31)` defaults to midnight (00:00:00) and excludes all data from that day.
|
|
149
|
+
|
|
150
|
+
---
|
|
151
|
+
|
|
152
|
+
## Entity ID Resolution
|
|
153
|
+
|
|
154
|
+
**NEVER** use entity names directly in API calls -- all filters require 64-character hex Vortexa IDs.
|
|
155
|
+
|
|
156
|
+
**ALWAYS** specify `filter_layer` when searching geographies. Without it, "China" returns ports, regions, and the country.
|
|
157
|
+
|
|
158
|
+
**ALWAYS** handle multiple search matches with disambiguation -- present top matches to the user and confirm.
|
|
159
|
+
|
|
160
|
+
```python
|
|
161
|
+
from vortexasdk import Products, Geographies, Vessels, Corporations
|
|
162
|
+
|
|
163
|
+
# Products: use filter_layer to get the right hierarchy level
|
|
164
|
+
Products().search(term="crude", exact_term_match=False).to_df()
|
|
165
|
+
# Pick the row where name == "Crude & Condensates" and layer == "group"
|
|
166
|
+
|
|
167
|
+
# Geographies: use filter_layer to disambiguate
|
|
168
|
+
Geographies().search(term="Rotterdam", filter_layer="port").to_df()
|
|
169
|
+
|
|
170
|
+
# Vessels: search by name, IMO, or vessel class
|
|
171
|
+
Vessels().search(term="Olympic Pride").to_df()
|
|
172
|
+
Vessels().search(vessel_classes="oil_vlcc").to_df()
|
|
173
|
+
|
|
174
|
+
# Corporations: search by name
|
|
175
|
+
Corporations().search(term="Shell").to_df()
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
See `guardrails.md` for the full entity resolution rules and common mistakes.
|
|
179
|
+
|
|
180
|
+
---
|
|
181
|
+
|
|
182
|
+
## Parameter Reference: CargoTimeSeries
|
|
183
|
+
|
|
184
|
+
**Endpoint:** `POST /v5/cargo/time-series`
|
|
185
|
+
**SDK:** `CargoTimeSeries().search(...)`
|
|
186
|
+
**Purpose:** Aggregate cargo flow volumes over time with optional breakdowns.
|
|
187
|
+
|
|
188
|
+
### Required Parameters
|
|
189
|
+
|
|
190
|
+
| Parameter | Type | Description | CRITICAL Notes |
|
|
191
|
+
|---|---|---|---|
|
|
192
|
+
| `filter_activity` | string | Which cargo state to filter on | See Activity Selection Table. NEVER rely on default. |
|
|
193
|
+
| `filter_time_min` | datetime | Start of time range (UTC) | ALWAYS specify explicitly. |
|
|
194
|
+
| `filter_time_max` | datetime | End of time range (UTC) | **MUST include time component** `datetime(Y, M, D, 23, 59, 59)` to capture final day. |
|
|
195
|
+
|
|
196
|
+
### Key Optional Parameters
|
|
197
|
+
|
|
198
|
+
| Parameter | Type | Default | Description | CRITICAL Notes |
|
|
199
|
+
|---|---|---|---|---|
|
|
200
|
+
| `timeseries_frequency` | enum | `day` | Time bucket: `day`, `week`, `doe_week`, `month`, `quarter`, `year` | See `date-units.md` for selection guidance. |
|
|
201
|
+
| `timeseries_unit` | enum | `b` | Output unit: `b`, `bpd`, `t`, `tpd`, `cbm`, `c`, `cpd`, `mpd`, `bpa`, `tpa`, `mpa` | Match to commodity. See `date-units.md`. |
|
|
202
|
+
| `timeseries_property` | enum | `quantity` | Split/breakdown dimension. `quantity` = no breakdown. | See Breakdown Properties below. |
|
|
203
|
+
| `timeseries_activity` | enum | same as `filter_activity` | Which activity timestamp to aggregate on | Only set differently for advanced use. See timeseries_activity vs filter_activity. |
|
|
204
|
+
| `filter_products` | string[] | none | Vortexa product IDs | Resolve via Products().search() first. |
|
|
205
|
+
| `filter_origins` | string[] | none | Vortexa geography IDs for origin | Use with `loading_end` for exports. |
|
|
206
|
+
| `filter_destinations` | string[] | none | Vortexa geography IDs for destination | Use with `unloading_start` for imports. |
|
|
207
|
+
| `filter_vessel_classes` | enum[] | none | Vessel class codes | See Vessel Classes table. |
|
|
208
|
+
| `filter_charterers` | string[] | none | Vortexa corporation IDs | |
|
|
209
|
+
| `filter_effective_controllers` | string[] | none | Vortexa corporation IDs | |
|
|
210
|
+
| `filter_vessel_owners` | string[] | none | Vortexa corporation IDs | |
|
|
211
|
+
| `filter_time_charterers` | string[] | none | Vortexa corporation IDs | |
|
|
212
|
+
| `filter_vessels` | string[] | none | Vortexa vessel IDs | |
|
|
213
|
+
| `filter_waypoints` | string[] | none | Geography IDs for waypoint (e.g., Suez Canal) | |
|
|
214
|
+
| `filter_storage_locations` | string[] | none | Geography IDs for floating storage location | Use with `storing_state`. |
|
|
215
|
+
| `filter_ship_to_ship_locations` | string[] | none | Geography IDs for STS location | |
|
|
216
|
+
| `filter_vessel_age_min` | number | none | Minimum vessel age in years | |
|
|
217
|
+
| `filter_vessel_age_max` | number | none | Maximum vessel age in years | |
|
|
218
|
+
| `filter_vessel_scrubbers` | enum | `disabled` | `disabled`, `inc` (with scrubbers), `exc` (without) | |
|
|
219
|
+
| `filter_vessel_flags` | string[] | none | Geography IDs for vessel flag state | |
|
|
220
|
+
| `filter_buyer` | string[] | none | Buyer corporation IDs | |
|
|
221
|
+
| `filter_seller` | string[] | none | Seller corporation IDs | |
|
|
222
|
+
| `filter_contract_type` | enum[] | none | `spot`, `term` | |
|
|
223
|
+
| `filter_delivery_method` | enum[] | none | `FOB`, `DES`, `CFR`, `CIF` | |
|
|
224
|
+
| `filter_shipper` | string[] | none | Shipper corporation IDs | |
|
|
225
|
+
| `filter_consignee` | string[] | none | Consignee corporation IDs | |
|
|
226
|
+
| `filter_hard_data` | enum[] | none | Data source confidence: `external`, `model`, `bol`, `port`, `fixture`, `market_analyst` | |
|
|
227
|
+
| `filter_confidence` | enum | `low` | Minimum confidence level. `low` = all data included. | Set higher for high-confidence analysis only. |
|
|
228
|
+
| `intra_movements` | enum | `all` | `all`, `exclude_intra_country`, `exclude_intra_geography` | ALWAYS set `exclude_intra_country` for exports/imports. |
|
|
229
|
+
| `quantity_at_time_of` | enum | `load` | `load` or `unload`. Controls loaded vs discharged volume. | Use `unload` for LNG discharged volumes (boil-off). |
|
|
230
|
+
| `timeseries_activity_time_span_min` | number | none | Minimum activity duration in milliseconds | For long-term storage: e.g., >14 days = `1000*60*60*24*14`. |
|
|
231
|
+
| `timeseries_activity_time_span_max` | number | none | Maximum activity duration in milliseconds | For short-term storage filtering. |
|
|
232
|
+
| `exclude_ship_to_ship` | boolean | false | Exclude all STS movements from results | Set `true` to remove STS transfers entirely. |
|
|
233
|
+
|
|
234
|
+
**Exclusion filters:** Most filter parameters have `exclude_` counterparts (e.g., `exclude_origins`, `exclude_products`, `exclude_vessels`, `exclude_vessel_classes`, `exclude_charterers`, `exclude_effective_controllers`, `exclude_vessel_flags`, `exclude_waypoints`, `exclude_destinations`, `exclude_owners`, `exclude_vessel_owners`, `exclude_time_charterers`, `exclude_ship_to_ship_locations`, `exclude_storage_locations`).
|
|
235
|
+
|
|
236
|
+
### Activity Filter Values
|
|
237
|
+
|
|
238
|
+
**Timestamps** (event occurred within the time window):
|
|
239
|
+
|
|
240
|
+
| Value | Meaning |
|
|
241
|
+
|---|---|
|
|
242
|
+
| `identified_for_loading_at` | When algorithms first detect a future movement |
|
|
243
|
+
| `loading_start` | When cargo begins loading onto vessel |
|
|
244
|
+
| `loading_end` | When vessel departs port of origin |
|
|
245
|
+
| `storing_start` | When vessel enters floating storage |
|
|
246
|
+
| `storing_end` | When floating storage period ends |
|
|
247
|
+
| `unloading_start` | When vessel arrives at destination port |
|
|
248
|
+
| `unloading_end` | When vessel is fully discharged |
|
|
249
|
+
| `ship_to_ship_start` | When STS transfer begins |
|
|
250
|
+
| `ship_to_ship_end` | When STS transfer ends |
|
|
251
|
+
| `waypoint_start` | When ship enters a waypoint |
|
|
252
|
+
| `waypoint_end` | When ship exits a waypoint |
|
|
253
|
+
|
|
254
|
+
**States** (movement was in this state at any point during the time window):
|
|
255
|
+
|
|
256
|
+
| Value | Meaning | Common User Term |
|
|
257
|
+
|---|---|---|
|
|
258
|
+
| `loading_state` | Cargo is being loaded | "loadings" |
|
|
259
|
+
| `unloading_state` | Cargo is being unloaded | "discharged" |
|
|
260
|
+
| `transiting_state` | Vessel is en route | "in transit" |
|
|
261
|
+
| `storing_state` | Movement is in floating storage | "floating storage" |
|
|
262
|
+
| `cargo_on_water_state` | Between departing origin and arriving destination | "on the water", "afloat" |
|
|
263
|
+
| `identified_for_loading_state` | Between detection and loading start | "identified for loading" |
|
|
264
|
+
| `unloaded_state` | After full discharge | "completed" |
|
|
265
|
+
| `any_activity` | Any state during the time period | "everything" |
|
|
266
|
+
|
|
267
|
+
**Note:** `oil_on_water_state` is DEPRECATED -- always use `cargo_on_water_state`.
|
|
268
|
+
|
|
269
|
+
### Breakdown Properties (timeseries_property / split_property)
|
|
270
|
+
|
|
271
|
+
Set `timeseries_property` (also referred to as the "split property" or breakdown dimension) to split aggregate results into sub-categories.
|
|
272
|
+
|
|
273
|
+
**Geographic breakdowns:**
|
|
274
|
+
|
|
275
|
+
| Value | Splits By | Example Use |
|
|
276
|
+
|---|---|---|
|
|
277
|
+
| `origin_country` | Origin country | "exports by source country" |
|
|
278
|
+
| `origin_port` | Origin port | "exports by loading port" |
|
|
279
|
+
| `origin_terminal` | Origin terminal | "terminal-level loading detail" |
|
|
280
|
+
| `origin_region` | Origin region | "exports by origin region" |
|
|
281
|
+
| `origin_shipping_region_v2` | Origin shipping region v2 | "exports by shipping region" |
|
|
282
|
+
| `origin_wider_shipping_region` | Origin wider shipping region | "broad origin grouping" |
|
|
283
|
+
| `origin_trading_region` | Origin trading region | "by trading region" |
|
|
284
|
+
| `origin_trading_sub_region` | Origin trading sub-region | "by trading sub-region" |
|
|
285
|
+
| `origin_basin` | Origin basin | "by origin basin" |
|
|
286
|
+
| `origin_country_zone` | Origin country zone | "by country zone" |
|
|
287
|
+
| `origin_state_or_province` | Origin state or province | "by US state" |
|
|
288
|
+
| `destination_country` | Destination country | "imports by receiving country" |
|
|
289
|
+
| `destination_port` | Destination port | "imports by discharge port" |
|
|
290
|
+
| `destination_terminal` | Destination terminal | "terminal-level discharge detail" |
|
|
291
|
+
| `destination_region` | Destination region | "imports by destination region" |
|
|
292
|
+
| `destination_shipping_region_v2` | Destination shipping region v2 | "imports by shipping region" |
|
|
293
|
+
| `destination_wider_shipping_region` | Destination wider shipping region | "broad destination grouping" |
|
|
294
|
+
| `destination_trading_region` | Destination trading region | "by destination trading region" |
|
|
295
|
+
| `destination_trading_sub_region` | Destination trading sub-region | "by destination trading sub-region" |
|
|
296
|
+
| `destination_basin` | Destination basin | "by destination basin" |
|
|
297
|
+
| `destination_country_zone` | Destination country zone | "by destination country zone" |
|
|
298
|
+
| `destination_state_or_province` | Destination state or province | "by destination state" |
|
|
299
|
+
| `storage_location_country` | Storage country | "floating storage by country" |
|
|
300
|
+
| `storage_location_region` | Storage region | "floating storage by region" |
|
|
301
|
+
| `storage_location_shipping_region_v2` | Storage shipping region v2 | "floating storage by shipping region" |
|
|
302
|
+
| `storage_location_trading_sub_region` | Storage trading sub-region | "storage by trading sub-region" |
|
|
303
|
+
| `waypoint_selected` | Waypoint | "by transit waypoint" |
|
|
304
|
+
|
|
305
|
+
**Product breakdowns:**
|
|
306
|
+
|
|
307
|
+
| Value | Splits By | Example Use |
|
|
308
|
+
|---|---|---|
|
|
309
|
+
| `product_group` | Major product group (Crude, CPP, DPP, LPG, LNG) | "by product type" |
|
|
310
|
+
| `product_group_product` | Sub-group product | "by product sub-group" |
|
|
311
|
+
| `product_category` | Product category | "by product category" |
|
|
312
|
+
| `product_grade` | Specific grade (e.g., Arab Light) | "by crude grade" |
|
|
313
|
+
|
|
314
|
+
**Vessel breakdowns:**
|
|
315
|
+
|
|
316
|
+
| Value | Splits By | Example Use |
|
|
317
|
+
|---|---|---|
|
|
318
|
+
| `vessel_class_group` | Top-level vessel type (oil, lpg, lng) | "by vessel type" |
|
|
319
|
+
| `vessel_class_coarse` | Coarse vessel class | "by vessel class (coarse)" |
|
|
320
|
+
| `vessel_class_granular` | Granular vessel class (most detailed) | "by vessel class (detailed)" |
|
|
321
|
+
| `vessel_flag` | Vessel flag state | "by flag state" |
|
|
322
|
+
|
|
323
|
+
**Commercial breakdowns:**
|
|
324
|
+
|
|
325
|
+
| Value | Splits By | Example Use |
|
|
326
|
+
|---|---|---|
|
|
327
|
+
| `shipper` | Shipper | "by shipper" |
|
|
328
|
+
| `consignee` | Consignee | "by consignee" |
|
|
329
|
+
| `load_buyer` | Buyer at load | "by buyer" |
|
|
330
|
+
| `discharge_buyer` | Buyer at discharge | "by discharge buyer" |
|
|
331
|
+
| `load_seller` | Seller at load | "by seller" |
|
|
332
|
+
| `discharge_seller` | Seller at discharge | "by discharge seller" |
|
|
333
|
+
| `contract_type` | Spot vs Term | "by contract type" |
|
|
334
|
+
| `delivery_method` | FOB, DES, CFR, CIF | "by delivery method" |
|
|
335
|
+
|
|
336
|
+
### Response Format
|
|
337
|
+
|
|
338
|
+
**Without breakdown** (`timeseries_property="quantity"` or omitted):
|
|
339
|
+
```json
|
|
340
|
+
{
|
|
341
|
+
"data": [
|
|
342
|
+
{"key": "2025-01-01T00:00:00.000Z", "value": 458665.0, "count": 12},
|
|
343
|
+
{"key": "2025-02-01T00:00:00.000Z", "value": 445024.0, "count": 11}
|
|
344
|
+
]
|
|
345
|
+
}
|
|
346
|
+
```
|
|
347
|
+
- `key`: timestamp for the time bucket
|
|
348
|
+
- `value`: aggregate volume in the requested unit
|
|
349
|
+
- `count`: number of cargo movements contributing
|
|
350
|
+
|
|
351
|
+
**With breakdown** (any `timeseries_property` other than `quantity`):
|
|
352
|
+
```json
|
|
353
|
+
{
|
|
354
|
+
"data": [
|
|
355
|
+
{
|
|
356
|
+
"key": "2025-01-01T00:00:00.000Z",
|
|
357
|
+
"value": 458665.0,
|
|
358
|
+
"count": 12,
|
|
359
|
+
"breakdown": [
|
|
360
|
+
{"label": "China", "value": 250000.0},
|
|
361
|
+
{"label": "Japan", "value": 120000.0},
|
|
362
|
+
{"label": "South Korea", "value": 88665.0}
|
|
363
|
+
]
|
|
364
|
+
}
|
|
365
|
+
]
|
|
366
|
+
}
|
|
367
|
+
```
|
|
368
|
+
|
|
369
|
+
---
|
|
370
|
+
|
|
371
|
+
## Parameter Reference: CargoMovements Search
|
|
372
|
+
|
|
373
|
+
**Endpoint:** `POST /v5/cargo/search`
|
|
374
|
+
**SDK:** `CargoMovements().search(...)`
|
|
375
|
+
**Purpose:** Retrieve individual cargo movement records with full event, vessel, product, and corporate entity detail.
|
|
376
|
+
|
|
377
|
+
**NEVER** rely on the default `size=1` -- always set `size=500` for batch retrieval.
|
|
378
|
+
|
|
379
|
+
### Additional Parameters (beyond CargoTimeSeries filters)
|
|
380
|
+
|
|
381
|
+
| Parameter | Type | Default | Description | CRITICAL Notes |
|
|
382
|
+
|---|---|---|---|---|
|
|
383
|
+
| `cm_unit` | enum | `b` | Unit for quantity fields: `b`, `t`, `cbm` | Only absolute units (no rate units like `bpd`). |
|
|
384
|
+
| `size` | integer | `1` | Records per page (0-500) | **Default is 1 -- ALWAYS set higher.** |
|
|
385
|
+
| `order` | enum | `_id` | Sort field: `_id`, `loading_start`, `loading_end`, `unloading_start`, `unloading_end`, `vessel_name`, `quantity`, `charterer`, `product`, `origin`, `destination`, `grade`, `shipper`, `consignee` | |
|
|
386
|
+
| `order_direction` | enum | `asc` | `asc` or `desc` | |
|
|
387
|
+
| `search_after` | object | none | Pagination cursor from previous response's `next_request` | Not offset-based -- use `next_request` from response. |
|
|
388
|
+
|
|
389
|
+
### DataFrame Column Naming Convention
|
|
390
|
+
|
|
391
|
+
The SDK flattens nested cargo movement structures using dot notation with zero-based indexes.
|
|
392
|
+
|
|
393
|
+
**Cargo-level fields:**
|
|
394
|
+
- `cargo_movement_id`, `quantity`, `discharge_quantity`, `status`
|
|
395
|
+
|
|
396
|
+
**Product hierarchy:**
|
|
397
|
+
- `product.group.label`, `product.group_product.label`, `product.category.label`, `product.grade.label`
|
|
398
|
+
- Each also has `.id`, `.layer`, `.probability`, `.source`
|
|
399
|
+
|
|
400
|
+
**Load event location:**
|
|
401
|
+
- `events.cargo_port_load_event.0.location.{terminal|port|country|region|shipping_region_v2|trading_region|trading_subregion}.label`
|
|
402
|
+
- `events.cargo_port_load_event.0.{start_timestamp|end_timestamp}`
|
|
403
|
+
|
|
404
|
+
**Unload event location:**
|
|
405
|
+
- `events.cargo_port_unload_event.0.location.{terminal|port|country|region|shipping_region_v2|trading_region|trading_subregion}.label`
|
|
406
|
+
- `events.cargo_port_unload_event.0.{start_timestamp|end_timestamp}`
|
|
407
|
+
|
|
408
|
+
**Vessel info (first vessel):**
|
|
409
|
+
- `vessels.0.{name|imo|mmsi|vessel_class|dwt|cubic_capacity|status}`
|
|
410
|
+
- For STS movements, subsequent vessels use `vessels.1.*`, `vessels.2.*`, etc.
|
|
411
|
+
|
|
412
|
+
**Corporate entities (at vessel level, NOT cargo level):**
|
|
413
|
+
- `vessels.0.corporate_entities.charterer.label`
|
|
414
|
+
- `vessels.0.corporate_entities.effective_controller.label`
|
|
415
|
+
- `vessels.0.corporate_entities.time_charterer.label`
|
|
416
|
+
|
|
417
|
+
**STS events:**
|
|
418
|
+
- `events.cargo_sts_event.0.location.{country|port|region|shipping_region_v2}.label`
|
|
419
|
+
- `events.cargo_sts_event.0.{from_vessel_name|to_vessel_name|start_timestamp|end_timestamp}`
|
|
420
|
+
|
|
421
|
+
**Storage events:**
|
|
422
|
+
- `events.cargo_storage_event.0.{start_timestamp|end_timestamp|vessel_id}`
|
|
423
|
+
|
|
424
|
+
**FSO load/unload events:**
|
|
425
|
+
- `events.cargo_fso_load_event.0.location.*`, `events.cargo_fso_unload_event.0.location.*`
|
|
426
|
+
|
|
427
|
+
**Parent IDs (genealogy):**
|
|
428
|
+
- `parent_ids.0.id`, `parent_ids.0.splinter_timestamp`
|
|
429
|
+
|
|
430
|
+
**Default columns** (when `columns=None`):
|
|
431
|
+
```python
|
|
432
|
+
[
|
|
433
|
+
'events.cargo_port_load_event.0.location.port.label',
|
|
434
|
+
'events.cargo_port_unload_event.0.location.port.label',
|
|
435
|
+
'product.group.label',
|
|
436
|
+
'product.grade.label',
|
|
437
|
+
'quantity',
|
|
438
|
+
'discharge_quantity',
|
|
439
|
+
'vessels.0.name',
|
|
440
|
+
'events.cargo_port_load_event.0.end_timestamp',
|
|
441
|
+
'events.cargo_port_unload_event.0.start_timestamp',
|
|
442
|
+
]
|
|
443
|
+
```
|
|
444
|
+
|
|
445
|
+
Use `columns='all'` for the full flattened view. Use a specific column list for targeted analysis.
|
|
446
|
+
|
|
447
|
+
**Common column map for renaming:**
|
|
448
|
+
```python
|
|
449
|
+
column_map = {
|
|
450
|
+
'cargo_movement_id': 'cargo_id',
|
|
451
|
+
'quantity': 'quantity',
|
|
452
|
+
'discharge_quantity': 'discharge_quantity',
|
|
453
|
+
'status': 'status',
|
|
454
|
+
'product.group.label': 'product_group',
|
|
455
|
+
'product.grade.label': 'product_grade',
|
|
456
|
+
'events.cargo_port_load_event.0.location.port.label': 'load_port',
|
|
457
|
+
'events.cargo_port_load_event.0.location.country.label': 'load_country',
|
|
458
|
+
'events.cargo_port_load_event.0.location.shipping_region_v2.label': 'load_shipping_region',
|
|
459
|
+
'events.cargo_port_unload_event.0.location.port.label': 'unload_port',
|
|
460
|
+
'events.cargo_port_unload_event.0.location.country.label': 'unload_country',
|
|
461
|
+
'events.cargo_port_unload_event.0.location.shipping_region_v2.label': 'unload_shipping_region',
|
|
462
|
+
'vessels.0.name': 'vessel_name',
|
|
463
|
+
'vessels.0.imo': 'vessel_imo',
|
|
464
|
+
'vessels.0.vessel_class': 'vessel_class',
|
|
465
|
+
'vessels.0.corporate_entities.charterer.label': 'charterer',
|
|
466
|
+
'vessels.0.corporate_entities.effective_controller.label': 'effective_controller',
|
|
467
|
+
}
|
|
468
|
+
```
|
|
469
|
+
|
|
470
|
+
---
|
|
471
|
+
|
|
472
|
+
## Parameter Reference: CargoMovements Record
|
|
473
|
+
|
|
474
|
+
**Endpoint:** `GET /v5/cargo/{id}`
|
|
475
|
+
**SDK:** `CargoMovements().record(id, params={'unit': 'b'})`
|
|
476
|
+
**Purpose:** Look up a single cargo movement by its ID.
|
|
477
|
+
|
|
478
|
+
| Parameter | Type | Description |
|
|
479
|
+
|---|---|---|
|
|
480
|
+
| `id` | string | Cargo movement ID (long or short format) |
|
|
481
|
+
| `unit` | enum | `b`, `t`, or `cbm` |
|
|
482
|
+
|
|
483
|
+
---
|
|
484
|
+
|
|
485
|
+
## What is a Cargo Movement
|
|
486
|
+
|
|
487
|
+
A cargo movement represents a **journey of a quantity of product between places**. It is the base data unit of the Vortexa API. Each movement has:
|
|
488
|
+
|
|
489
|
+
- **Events**: loading, unloading, STS transfers, storage, waypoints -- each with location and timestamps
|
|
490
|
+
- **Vessels**: one or more vessels that carried the cargo, each with corporate entities (charterer, effective controller, time charterer, owner)
|
|
491
|
+
- **Product**: hierarchical classification (group -> group_product -> category -> grade)
|
|
492
|
+
- **Quantity**: volume in the selected unit; `discharge_quantity` may differ from `quantity` for LNG due to boil-off gas
|
|
493
|
+
|
|
494
|
+
### Ship-to-Ship Transfers (STS)
|
|
495
|
+
|
|
496
|
+
A single cargo movement tracks from origin to final destination even if STS transfers occur mid-journey. The STS events are recorded in the `events` array. The movement retains one ID throughout.
|
|
497
|
+
|
|
498
|
+
Use `exclude_ship_to_ship=true` to remove all STS movements from results when analysing direct port-to-port flows only.
|
|
499
|
+
|
|
500
|
+
### Cargo Splits (Co-loads / Co-discharges / Genealogy)
|
|
501
|
+
|
|
502
|
+
When cargo splits (partial STS discharge, partial port discharge), new cargo movement IDs are created. The relationship is captured in `parent_ids`:
|
|
503
|
+
|
|
504
|
+
- `parent_ids` lists ancestors in genealogical order: immediate parent first, root last
|
|
505
|
+
- `splinter_timestamp` records when the split occurred
|
|
506
|
+
- Co-loaded parcels (multiple grades on same vessel) are distinct movements from the start
|
|
507
|
+
|
|
508
|
+
**CRITICAL for analysis:**
|
|
509
|
+
- When summing cargo movements manually, be aware of parent-child relationships to avoid double-counting
|
|
510
|
+
- **CargoTimeSeries handles this automatically** -- ALWAYS prefer it for aggregate volume questions
|
|
511
|
+
|
|
512
|
+
### Data Revisions
|
|
513
|
+
|
|
514
|
+
Vortexa continuously updates cargo data. Revisions include:
|
|
515
|
+
- New movements appearing (vessel starts loading)
|
|
516
|
+
- Movements being dropped (false positive corrected)
|
|
517
|
+
- Property updates without ID change (product, timestamps within same week, corporate entities)
|
|
518
|
+
- ID changes when the start of movement shifts to a different calendar week (old ID dropped, new one created)
|
|
519
|
+
|
|
520
|
+
Dropped IDs are no longer available. There is no changelog -- `parent_ids` reflects the latest view, not historical state.
|
|
521
|
+
|
|
522
|
+
### Boil-Off Gas (LNG)
|
|
523
|
+
|
|
524
|
+
LNG evaporates during transit (~0.1-0.2% per day). This means:
|
|
525
|
+
- `discharge_quantity` < `quantity` for LNG movements
|
|
526
|
+
- Use `quantity_at_time_of="load"` for loaded volume or `"unload"` for discharged volume
|
|
527
|
+
- Default is `"load"`
|
|
528
|
+
- For non-LNG, `discharge_quantity` equals `quantity`
|
|
529
|
+
|
|
530
|
+
---
|
|
531
|
+
|
|
532
|
+
## Intra-Movements (Domestic Flow Control)
|
|
533
|
+
|
|
534
|
+
| Value | Behavior | Use When |
|
|
535
|
+
|---|---|---|
|
|
536
|
+
| `all` | Include all movements including domestic | Total volumes regardless of destination |
|
|
537
|
+
| `exclude_intra_country` | Exclude same-country origin/destination | International trade (most common for exports/imports) |
|
|
538
|
+
| `exclude_intra_geography` | Exclude same-region origin/destination | Cross-regional analysis |
|
|
539
|
+
|
|
540
|
+
**Example:** Russia as origin, West of Suez as destination:
|
|
541
|
+
- `all`: shows everything including Russia-to-Russia
|
|
542
|
+
- `exclude_intra_country`: Russia to West of Suez, excluding Russia-to-Russia
|
|
543
|
+
- `exclude_intra_geography`: excludes both Russia-to-Russia AND West of Suez-to-West of Suez internal flows
|
|
544
|
+
|
|
545
|
+
---
|
|
546
|
+
|
|
547
|
+
## Worked Examples
|
|
548
|
+
|
|
549
|
+
### Example 1: Simple Export Volume Trend
|
|
550
|
+
|
|
551
|
+
**User:** "Show me monthly crude exports from Saudi Arabia in 2025"
|
|
552
|
+
|
|
553
|
+
**Analysis:**
|
|
554
|
+
- "monthly" -> `timeseries_frequency="month"`
|
|
555
|
+
- "crude" -> resolve "Crude & Condensates" group ID
|
|
556
|
+
- "exports" -> `filter_activity="loading_end"` + `intra_movements="exclude_intra_country"`
|
|
557
|
+
- "from Saudi Arabia" -> resolve Saudi Arabia country ID -> `filter_origins`
|
|
558
|
+
- "in 2025" -> `filter_time_min=datetime(2025,1,1)`, `filter_time_max=datetime(2025,12,31,23,59,59)`
|
|
559
|
+
- No unit specified + oil -> default to `bpd`
|
|
560
|
+
- Aggregate volume question -> **CargoTimeSeries**
|
|
561
|
+
|
|
562
|
+
```python
|
|
563
|
+
from vortexasdk import CargoTimeSeries, Geographies, Products
|
|
564
|
+
from datetime import datetime
|
|
565
|
+
|
|
566
|
+
saudi = [g.id for g in Geographies().search("Saudi Arabia", filter_layer="country").to_list()]
|
|
567
|
+
crude = [p.id for p in Products().search("crude").to_list() if p.name == "Crude & Condensates"]
|
|
568
|
+
|
|
569
|
+
df = CargoTimeSeries().search(
|
|
570
|
+
filter_activity="loading_end",
|
|
571
|
+
filter_time_min=datetime(2025, 1, 1),
|
|
572
|
+
filter_time_max=datetime(2025, 12, 31, 23, 59, 59),
|
|
573
|
+
filter_origins=saudi,
|
|
574
|
+
filter_products=crude,
|
|
575
|
+
intra_movements="exclude_intra_country",
|
|
576
|
+
timeseries_frequency="month",
|
|
577
|
+
timeseries_unit="bpd"
|
|
578
|
+
).to_df()
|
|
579
|
+
```
|
|
580
|
+
|
|
581
|
+
### Example 2: Flow with Breakdown
|
|
582
|
+
|
|
583
|
+
**User:** "How much crude does the Middle East export to Asia by destination country, weekly, in barrels per day?"
|
|
584
|
+
|
|
585
|
+
**Analysis:**
|
|
586
|
+
- "how much" + "weekly" -> CargoTimeSeries with `timeseries_frequency="week"`
|
|
587
|
+
- "crude" -> Crude & Condensates product group ID
|
|
588
|
+
- "export" -> `filter_activity="loading_end"` + `intra_movements="exclude_intra_country"`
|
|
589
|
+
- "from the Middle East" -> resolve MEG region ID -> `filter_origins`
|
|
590
|
+
- "to Asia" -> resolve Asia region ID -> `filter_destinations`
|
|
591
|
+
- "by destination country" -> `timeseries_property="destination_country"`
|
|
592
|
+
- "barrels per day" -> `timeseries_unit="bpd"`
|
|
593
|
+
|
|
594
|
+
```python
|
|
595
|
+
df = CargoTimeSeries().search(
|
|
596
|
+
filter_activity="loading_end",
|
|
597
|
+
filter_time_min=datetime(2025, 1, 1),
|
|
598
|
+
filter_time_max=datetime(2025, 6, 30, 23, 59, 59),
|
|
599
|
+
filter_origins=meg_ids,
|
|
600
|
+
filter_destinations=asia_ids,
|
|
601
|
+
filter_products=crude_ids,
|
|
602
|
+
intra_movements="exclude_intra_country",
|
|
603
|
+
timeseries_frequency="week",
|
|
604
|
+
timeseries_unit="bpd",
|
|
605
|
+
timeseries_property="destination_country"
|
|
606
|
+
).to_df()
|
|
607
|
+
```
|
|
608
|
+
|
|
609
|
+
**Response format with breakdown:** Each row has `key` (timestamp), `value` (total), `count`, and a `breakdown` array of `{label, value}` pairs for each destination country.
|
|
610
|
+
|
|
611
|
+
### Example 3: Individual Cargo Records
|
|
612
|
+
|
|
613
|
+
**User:** "List all VLCC crude cargoes that loaded from the US Gulf in January 2025"
|
|
614
|
+
|
|
615
|
+
**Analysis:**
|
|
616
|
+
- "list" + "cargoes" -> **CargoMovements search** (not TimeSeries)
|
|
617
|
+
- "VLCC" -> `filter_vessel_classes=["oil_vlcc"]`
|
|
618
|
+
- "crude" -> Crude product group ID -> `filter_products`
|
|
619
|
+
- "loaded" -> `filter_activity="loading_state"`
|
|
620
|
+
- "from the US Gulf" -> USG geography ID -> `filter_origins`
|
|
621
|
+
- "January 2025" -> `filter_time_min=datetime(2025,1,1)`, `filter_time_max=datetime(2025,1,31,23,59,59)`
|
|
622
|
+
|
|
623
|
+
```python
|
|
624
|
+
from vortexasdk import CargoMovements
|
|
625
|
+
|
|
626
|
+
df = CargoMovements().search(
|
|
627
|
+
filter_activity="loading_state",
|
|
628
|
+
filter_time_min=datetime(2025, 1, 1),
|
|
629
|
+
filter_time_max=datetime(2025, 1, 31, 23, 59, 59),
|
|
630
|
+
filter_origins=usg_ids,
|
|
631
|
+
filter_products=crude_ids,
|
|
632
|
+
filter_vessel_classes=["oil_vlcc"],
|
|
633
|
+
cm_unit="b",
|
|
634
|
+
size=500
|
|
635
|
+
).to_df(columns="all")
|
|
636
|
+
```
|
|
637
|
+
|
|
638
|
+
### Example 4: Floating Storage
|
|
639
|
+
|
|
640
|
+
**User:** "What are the current floating storage levels for crude in the Middle East?"
|
|
641
|
+
|
|
642
|
+
**Analysis:**
|
|
643
|
+
- "floating storage" -> `filter_activity="storing_state"`
|
|
644
|
+
- "current" -> recent time window (last 7 days)
|
|
645
|
+
- "crude" -> Crude product group ID
|
|
646
|
+
- "in the Middle East" -> `filter_storage_locations=[meg_id]`
|
|
647
|
+
- Aggregate question -> **CargoTimeSeries**
|
|
648
|
+
|
|
649
|
+
```python
|
|
650
|
+
df = CargoTimeSeries().search(
|
|
651
|
+
filter_activity="storing_state",
|
|
652
|
+
filter_time_min=datetime(2025, 6, 1),
|
|
653
|
+
filter_time_max=datetime(2025, 6, 7, 23, 59, 59),
|
|
654
|
+
filter_products=crude_ids,
|
|
655
|
+
filter_storage_locations=meg_ids,
|
|
656
|
+
timeseries_frequency="day",
|
|
657
|
+
timeseries_unit="b"
|
|
658
|
+
).to_df()
|
|
659
|
+
```
|
|
660
|
+
|
|
661
|
+
### Example 5: Excluding Domestic Flows
|
|
662
|
+
|
|
663
|
+
**User:** "Show me Russian crude exports, excluding domestic movements"
|
|
664
|
+
|
|
665
|
+
**Analysis:**
|
|
666
|
+
- "exports" -> `filter_activity="loading_end"` + `intra_movements="exclude_intra_country"`
|
|
667
|
+
- "excluding domestic" is already implied by `exclude_intra_country`, but explicitly stated here for clarity
|
|
668
|
+
- "Russian" -> resolve Russia country ID -> `filter_origins`
|
|
669
|
+
- "crude" -> resolve Crude & Condensates group ID -> `filter_products`
|
|
670
|
+
|
|
671
|
+
```python
|
|
672
|
+
df = CargoTimeSeries().search(
|
|
673
|
+
filter_activity="loading_end",
|
|
674
|
+
filter_origins=russia_ids,
|
|
675
|
+
filter_products=crude_ids,
|
|
676
|
+
intra_movements="exclude_intra_country",
|
|
677
|
+
timeseries_frequency="month",
|
|
678
|
+
timeseries_unit="bpd",
|
|
679
|
+
filter_time_min=datetime(2025, 1, 1),
|
|
680
|
+
filter_time_max=datetime(2025, 12, 31, 23, 59, 59)
|
|
681
|
+
).to_df()
|
|
682
|
+
```
|
|
683
|
+
|
|
684
|
+
---
|
|
685
|
+
|
|
686
|
+
## Defaults When Omitted
|
|
687
|
+
|
|
688
|
+
| Parameter | Default | Risk | Recommendation |
|
|
689
|
+
|---|---|---|---|
|
|
690
|
+
| `filter_activity` | `any_activity` | Matches ALL cargo states -- misleading aggregates | ALWAYS specify explicitly |
|
|
691
|
+
| `filter_time_min/max` | Current timestamp | Non-reproducible results | ALWAYS specify explicitly |
|
|
692
|
+
| `timeseries_frequency` | `day` | Too granular for long ranges | Match to date range (see `date-units.md`) |
|
|
693
|
+
| `timeseries_unit` | `b` (barrels) | Wrong for LNG (`t`) and rate queries (`bpd`) | Match to commodity and query type |
|
|
694
|
+
| `timeseries_property` | `quantity` | No breakdown applied | Set when user asks "by X" |
|
|
695
|
+
| `timeseries_activity` | same as `filter_activity` | Unexpected if user wants different aggregation | Only set differently for advanced use |
|
|
696
|
+
| `cm_unit` | `b` (search), `t` (REST) | Inconsistent between SDK and REST | Specify explicitly |
|
|
697
|
+
| `intra_movements` | `all` | Includes domestic flows, inflating export/import volumes | Set `exclude_intra_country` for international trade |
|
|
698
|
+
| `quantity_at_time_of` | `load` | For LNG, loaded != discharged due to boil-off | Use `unload` for delivered volumes |
|
|
699
|
+
| `size` (search only) | `1` | Returns only 1 record | ALWAYS set to 500 for batch retrieval |
|
|
700
|
+
| `filter_vessel_scrubbers` | `disabled` | No scrubber filter | Usually fine |
|
|
701
|
+
| `filter_confidence` | `low` | Includes all confidence levels | Set higher for high-confidence-only analysis |
|
|
702
|
+
|
|
703
|
+
---
|
|
704
|
+
|
|
705
|
+
## Error Recovery
|
|
706
|
+
|
|
707
|
+
| Symptom | Likely Cause | Fix |
|
|
708
|
+
|---|---|---|
|
|
709
|
+
| Empty results | Wrong entity IDs | Re-run entity search, verify names resolved to correct IDs |
|
|
710
|
+
| Empty results | Time range too narrow | Widen the time window to confirm data exists |
|
|
711
|
+
| Empty results | Wrong `filter_activity` | "exports" = `loading_end`, "imports" = `unloading_start` |
|
|
712
|
+
| Empty results | `intra_movements` excluding data | Try `all` first to confirm data exists, then re-add exclusion |
|
|
713
|
+
| Empty results | Over-filtering | Remove filters one at a time to isolate the issue |
|
|
714
|
+
| Only 1 record | `size` still at default | Set `size=500` for CargoMovements search |
|
|
715
|
+
| Volumes too low | Used `loading_state` instead of `loading_end` for exports | Change to `loading_end` |
|
|
716
|
+
| Volumes too high | `intra_movements="all"` including domestic | Set to `exclude_intra_country` |
|
|
717
|
+
| Unexpected volumes | LNG boil-off | Check `quantity_at_time_of` -- `load` vs `unload` differ for LNG |
|
|
718
|
+
| Unexpected volumes | Wrong product hierarchy level | `group` captures everything under it; `grade` is very specific |
|
|
719
|
+
| Unexpected volumes | `timeseries_activity` differs from `filter_activity` | Ensure they match unless intentionally different |
|
|
720
|
+
| Double-counting | Manual sum of split cargoes | Use CargoTimeSeries (handles splits automatically) or check `parent_ids` |
|
|
721
|
+
| Missing final day data | `filter_time_max` at midnight | Add time component: `datetime(Y, M, D, 23, 59, 59)` |
|
|
722
|
+
|
|
723
|
+
---
|
|
724
|
+
|
|
725
|
+
## Validation Checklist
|
|
726
|
+
|
|
727
|
+
Run through these before every API call:
|
|
728
|
+
|
|
729
|
+
1. `filter_time_min` is before `filter_time_max`
|
|
730
|
+
2. `filter_time_max` includes time component `(23, 59, 59)` for historical end dates
|
|
731
|
+
3. Time range does not exceed ~4 years per request (performance)
|
|
732
|
+
4. `size` is set to 500 for CargoMovements search (not default 1)
|
|
733
|
+
5. All ID-based filters use valid 64-character hex Vortexa IDs
|
|
734
|
+
6. `timeseries_unit` matches commodity: `b`/`bpd` for oil, `t`/`tpd` for LNG/LPG
|
|
735
|
+
7. `filter_activity` is explicitly set (not relying on `any_activity` default)
|
|
736
|
+
8. `intra_movements` is set to `exclude_intra_country` for exports/imports
|
|
737
|
+
9. Breakdown dimension (`timeseries_property`) is relevant to the query
|
|
738
|
+
10. For pagination, use `search_after` from `next_request` (not offset-based)
|