Setup¶
Install the Signal Ocean SDK:
pip install signal-ocean
Set your subscription key acquired here: https://apis.signalocean.com/profile
pip install signal-ocean
signal_ocean_api_key = '' #replace with your subscription key
Call the Voyages API¶
The Voyages API retrieves information about vessel voyages.
from signal_ocean import Connection
from signal_ocean.voyages import VoyagesAPI
from signal_ocean.voyages import Vessel, VesselFilter
from signal_ocean.voyages import VesselType, VesselTypeFilter
from signal_ocean.voyages import VesselClass, VesselClassFilter
import pandas as pd
from datetime import date, timedelta
connection = Connection(signal_ocean_api_key)
api = VoyagesAPI(connection)
Get voyages for vessel¶
# get the imo by using the vessel name
vessel = api.get_imos(VesselFilter('Blint'))[0]
vessel
Vessel(imo=9293002, vessel_name='Blint')
vessel_voyages = api.get_voyages(imo=9293002)
vessel_voyages_df = pd.DataFrame([v.__dict__ for v in vessel_voyages])
vessel_voyages_df.tail(5)
imo | voyage_number | vessel_type_id | vessel_class_id | vessel_status_id | commercial_operator_id | deleted | events | id | horizon_id | ... | predicted_ballast_distance | laden_distance | predicted_laden_distance | suez_crossing | panama_crossing | canakkale_crossing | bosporus_crossing | torres_strait_crossing | magellan_strait_crossing | great_belt_crossing | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
125 | 9293002 | 126 | 1 | 86 | 1 | 1597.0 | False | (VoyageEvent(id='I8DCCCASEDE4C9900', voyage_id... | I8DCCCAVEDE4C9900 | 1 | ... | None | 7915.09 | NaN | BallastHistorical, LadenHistorical | None | None | None | None | None | LadenHistorical |
126 | 9293002 | 127 | 1 | 86 | 1 | 1597.0 | False | (VoyageEvent(id='I8DCCCASEDE9BB300', voyage_id... | I8DCCCAVEDE9BB300 | 1 | ... | None | 7956.52 | NaN | BallastHistorical, LadenHistorical | None | None | None | None | None | LadenHistorical |
127 | 9293002 | 128 | 1 | 86 | 1 | 1597.0 | False | (VoyageEvent(id='I8DCCCASEDF125A00', voyage_id... | I8DCCCAVEDF125A00 | 1 | ... | None | 7961.28 | NaN | BallastHistorical, LadenHistorical | None | None | None | None | None | LadenHistorical |
128 | 9293002 | 129 | 1 | 86 | 1 | NaN | False | (VoyageEvent(id='I8DCCCASEDF617400', voyage_id... | I8DCCCAVEDF617400 | 1 | ... | None | 5931.72 | NaN | BallastHistorical, LadenHistorical | None | None | None | None | None | LadenHistorical |
129 | 9293002 | 130 | 1 | 86 | 1 | NaN | False | (VoyageEvent(id='I8DCCCASEDFD81B00', voyage_id... | I8DCCCAVEDFD81B00 | 2 | ... | None | 63.37 | 726.43 | None | None | None | None | None | None | None |
5 rows × 75 columns
vessel_events_df = pd.DataFrame(e.__dict__ for voyage_events in vessel_voyages_df['events'] for e in voyage_events)
vessel_events_df.tail(5)
id | voyage_id | event_type_id | event_type | event_horizon_id | event_horizon | purpose | event_date | arrival_date | sailing_date | ... | area_idlevel2 | area_name_level2 | area_idlevel3 | area_name_level3 | low_ais_density | quantity | quantity_unit_id | quantity_unit | quantity_in_barrels | event_details | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
724 | I8DCCCATEDFDC0F80 | None | 0 | Stop | 0 | Historical | Stop | NaT | 2025-06-12 19:59:10+00:00 | 2025-06-21 19:59:47+00:00 | ... | 103 | Red Sea | 84 | East | None | NaN | NaN | None | NaN | (VoyageEventDetail(id='I8DCCCALEDFDC0F80', eve... |
725 | I8DCCCATEDFE54A00 | None | 1 | PortCall | 0 | Historical | Discharge | NaT | 2025-06-24 03:59:17+00:00 | 2025-06-24 06:55:48+00:00 | ... | 103 | Red Sea | 84 | East | None | 102000.0 | 1.0 | MetricTonnes | 723115.0 | (VoyageEventDetail(id='I8DCCCALEDFE54A00', eve... |
726 | I8DCCCASEDFD81B00 | None | 2 | VoyageStart | 0 | Historical | Start | 2025-06-24 06:55:48+00:00 | NaT | NaT | ... | 103 | Red Sea | 84 | East | None | NaN | NaN | None | NaN | None |
727 | I8DCCCATEDFF27900 | None | 1 | PortCall | 1 | Current | Load | NaT | 2025-07-02 03:52:30+00:00 | 2025-07-11 17:02:33.745000+00:00 | ... | 25023 | India / Pakistan | 84 | East | None | 100000.0 | 1.0 | MetricTonnes | 724493.0 | (VoyageEventDetail(id='I8DCCCALEDFF27900', eve... |
728 | I8DCCCATEDFFFA800 | None | 1 | PortCall | 2 | Future | Discharge | NaT | 2025-07-14 06:09:17.754000+00:00 | 2025-07-16 21:40:59.243000+00:00 | ... | 25023 | India / Pakistan | 84 | East | True | 100000.0 | 1.0 | MetricTonnes | 724493.0 | None |
5 rows × 33 columns
vessel_event_details_df = pd.DataFrame(e.__dict__ for event_details in vessel_events_df['event_details'] for e in event_details or [])
vessel_event_details_df.tail(5)
id | event_id | event_detail_type | arrival_date | sailing_date | start_time_of_operation | end_time_of_operation | sts_id | geo_asset_id | geo_asset_name | latitude | longitude | other_vessel_imo | other_vessel_name | floating_storage_start_date | floating_storage_duration | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
622 | I8DCCCALEDFBDBD00 | None | Stop | 2025-05-26 11:45:23+00:00 | 2025-05-26 15:59:20+00:00 | NaT | NaT | None | 4116 | Paldiski Anchorage | 59.1670 | 21.4375 | NaN | None | NaT | NaN |
623 | I8DCCCALEDFD81B00 | None | Stop | 2025-06-11 11:55:25+00:00 | 2025-06-12 03:59:00+00:00 | NaT | NaT | None | 14573 | Port Said Anchorage | 31.4698 | 32.3213 | NaN | None | NaT | NaN |
624 | I8DCCCALEDFDC0F80 | None | Stop | 2025-06-12 19:59:10+00:00 | 2025-06-21 19:59:47+00:00 | NaT | NaT | None | 14489 | Suez Anchorage | 29.7230 | 32.6030 | NaN | None | 2025-06-12 19:59:10+00:00 | 9.0 |
625 | I8DCCCALEDFE54A00 | None | StS | 2025-06-24 03:59:17+00:00 | 2025-06-24 06:55:48+00:00 | 2025-06-24 03:59:17+00:00 | 2025-06-24 06:55:48+00:00 | 8CFD778DCCCA8DDB2D37D821880 | 4160 | Marsa Barshayer Anchorage | 19.3839 | 38.4933 | 9239927.0 | Daffodil | NaT | NaN |
626 | I8DCCCALEDFF27900 | None | Stop | 2025-07-02 03:52:30+00:00 | 2025-07-09 09:41:36+00:00 | NaT | NaT | None | 5113 | Jamnagar Refinery (Reliance) | 22.6507 | 69.9005 | NaN | None | NaT | NaN |
Get voyages for vessel class¶
#get vessel class id for vlcc
vc = api.get_vessel_classes(VesselClassFilter('vlcc'))[0]
vlcc_id = vc.vessel_class_id
vlcc_id
84
date_from = date.today() - timedelta(days=30)
recent_vlcc_voyages = api.get_voyages(vessel_class_id=vlcc_id, date_from=date_from)
recent_vlcc_voyages = pd.DataFrame([v.__dict__ for v in recent_vlcc_voyages])
recent_vlcc_voyages.tail(5)
imo | voyage_number | vessel_type_id | vessel_class_id | vessel_status_id | commercial_operator_id | deleted | events | id | horizon_id | ... | predicted_ballast_distance | laden_distance | predicted_laden_distance | suez_crossing | panama_crossing | canakkale_crossing | bosporus_crossing | torres_strait_crossing | magellan_strait_crossing | great_belt_crossing | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
395 | 9933652 | 15 | 1 | 84 | 1 | 558.0 | False | (VoyageEvent(id='I97935454SEDFD81B00', voyage_... | I97935454VEDFD81B00 | 2 | ... | 2267.48 | NaN | 9624.93 | None | None | None | None | None | None | None |
396 | 9937799 | 7 | 1 | 84 | 1 | 1031.0 | False | (VoyageEvent(id='I97A38754SEDFD81B00', voyage_... | I97A38754VEDFD81B00 | 2 | ... | NaN | NaN | NaN | None | None | None | None | None | BallastHistorical | None |
397 | 9941673 | 15 | 1 | 84 | 1 | 2236.0 | False | (VoyageEvent(id='I97B2A954SEDFD81B00', voyage_... | I97B2A954VEDFD81B00 | 2 | ... | NaN | 8.8 | 6475.67 | None | None | None | None | None | None | None |
398 | 9988695 | 1 | 1 | 84 | 1 | NaN | False | (VoyageEvent(id='I986A5754SEDFD81B00', voyage_... | I986A5754VEDFD81B00 | 2 | ... | NaN | NaN | NaN | None | None | None | None | None | None | None |
399 | 1037048 | 1 | 1 | 84 | 1 | 435.0 | False | (VoyageEvent(id='IFD2F854SEDFD81B00', voyage_i... | IFD2F854VEDFD81B00 | 2 | ... | 45.68 | NaN | NaN | None | None | None | None | None | None | None |
5 rows × 75 columns
Get voyages for vessel in flat format¶
# get the imo by using the vessel name
vessel = api.get_imos(VesselFilter('Sea'))[0]
vessel
Vessel(imo=1013494, vessel_name='Sea Energy')
vessel_voyages_flat = api.get_voyages_flat(imo=vessel.imo)
vessel_voyages_df = pd.DataFrame(v.__dict__ for v in vessel_voyages_flat.voyages)
vessel_voyages_df.tail(5)
vessel_events_df = pd.DataFrame(v.__dict__ for v in vessel_voyages_flat.events)
vessel_events_df.tail(5)
vessel_event_details_df = pd.DataFrame(v.__dict__ for v in vessel_voyages_flat.event_details)
vessel_event_details_df.tail(5)
vessel_voyages_geos_df = pd.DataFrame(v.__dict__ for v in vessel_voyages_flat.geos)
vessel_voyages_geos_df.tail(5)
Get voyages for vessel class in the flat format¶
#get vessel class id for vlcc
vc = api.get_vessel_classes(VesselClassFilter('vlcc'))[0]
vlcc_id = vc.vessel_class_id
date_from = date.today() - timedelta(days=30)
recent_vlcc_voyages_flat = api.get_voyages_flat(vessel_class_id=vlcc_id, date_from=date_from)
print('Voyages:', len(recent_vlcc_voyages_flat.voyages))
print('Events:', len(recent_vlcc_voyages_flat.events))
print('EventDetails:', len(recent_vlcc_voyages_flat.event_details))
print('Geos:', len(recent_vlcc_voyages_flat.geos))
Voyages: 400 Events: 1357 EventDetails: 483 Geos: 288
Get voyages for vessel incrementally¶
Initial requests retrieves voyages mathcing the query criteria and a query token that can be used in the subsequent request.
# get the imo by using the vessel name
vessel = api.get_imos(VesselFilter('XIN YONG YANG'))[0]
vessel
Vessel(imo=9416642, vessel_name='Xin Yong Yang')
vessel_voyages, next_request_token = api.get_incremental_voyages(imo=vessel.imo)
len(vessel_voyages)
92
Provided the token retrieved for the previous request, the subsequent request retrieves only voyages that have been updated since the previous request.
incremental_voyages, next_request_token = api.get_incremental_voyages(imo=9416642, incremental_token=next_request_token)
len(incremental_voyages)
0
The retrieved information is used to replace any modify voyages from the dataset. Note that returned voyages marked as deleted are only used to filter out voyages.
updated_voyage_ids = set(v.id for v in incremental_voyages)
vessel_voyages = [v for v in vessel_voyages if v.id not in updated_voyage_ids]
new_vessel_voyages = [v for v in incremental_voyages if not v.deleted]
vessel_voyages = sorted(vessel_voyages + new_vessel_voyages, key= lambda v: v.voyage_number)
len(vessel_voyages)
92
Get voyages for vessel class incrementally¶
Voyages for vessel class are retieved and updated in the same way incrementally.
#get vessel class id for vlcc
vc = api.get_vessel_classes(VesselClassFilter('vlcc'))[0]
vessel_class_id = vc.vessel_class_id
vessel_class_id
84
date_from = date.today() - timedelta(days=30)
voyages, next_request_token = api.get_incremental_voyages(vessel_class_id=vessel_class_id, date_from=date_from)
len(voyages)
400
incremental_voyages, next_request_token = api.get_incremental_voyages(vessel_class_id=vessel_class_id, date_from=date_from, incremental_token=next_request_token)
len(incremental_voyages)
0
updated_voyage_ids = set(v.id for v in incremental_voyages)
voyages = [v for v in voyages if v.id not in updated_voyage_ids and not v.deleted]
new_voyages = [v for v in incremental_voyages if not v.deleted]
voyages = sorted(voyages + new_voyages, key= lambda v: (v.imo, v.voyage_number))
len(voyages)
400
Get voyages for vessel class incrementally in the flat format¶
Voyages may be retrieved and updated incrementally in the flat format.
#get vessel class id for vlcc
vc = api.get_vessel_classes(VesselClassFilter('vlcc'))[0]
vessel_class_id = vc.vessel_class_id
vessel_class_id
84
date_from = date.today() - timedelta(days=30)
voyages_flat, next_request_token = api.get_incremental_voyages_flat(vessel_class_id=vessel_class_id, date_from=date_from)
voyages = voyages_flat.voyages
events = voyages_flat.events
event_details = voyages_flat.event_details
geos = voyages_flat.geos
len(voyages), len(events), len(event_details), len(geos)
(400, 1357, 483, 288)
incremental_voyages_flat, next_request_token = api.get_incremental_voyages_flat(vessel_class_id=vessel_class_id, date_from=date_from, incremental_token=next_request_token)
len(incremental_voyages_flat.voyages)
0
In this case the update step is applied to voyages, events, event details and geos datasets.
updated_voyage_ids = set(v.id for v in incremental_voyages_flat.voyages)
voyages = [v for v in voyages if v.id not in updated_voyage_ids and not v.deleted]
new_voyages = [v for v in incremental_voyages_flat.voyages if not v.deleted]
voyages = sorted(voyages + new_voyages, key= lambda v: (v.imo, v.voyage_number))
len(voyages)
400
updated_event_ids = set(e.id for e in events if e.voyage_id in updated_voyage_ids)
events = [e for e in events if e.id not in updated_event_ids]
events = sorted(events + list(incremental_voyages_flat.events), key= lambda e: e.id)
len(events)
1357
event_details = [e for e in event_details if e.id not in updated_event_ids]
event_details = sorted(event_details + list(incremental_voyages_flat.event_details), key= lambda e: e.id)
len(event_details)
483
updated_geo_ids = set(g.id for g in incremental_voyages_flat.geos)
geos = [g for g in geos if g.id not in updated_geo_ids] + list(incremental_voyages_flat.geos)
len(geos)
288