Skip to content

Commit 69bcd42

Browse files
committed
add new helpers
1 parent c5f9976 commit 69bcd42

1 file changed

Lines changed: 241 additions & 0 deletions

File tree

src/systemathics/apis/helpers/dataframe_helpers.py

Lines changed: 241 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@
1010
get_index_tick - Get Index tick data as a DataFrame using Ganymede gRPC API.
1111
get_future_daily - Get future daily data as a DataFrame using Ganymede gRPC API.
1212
get_equity_daily - Get equity daily data as a DataFrame using Ganymede gRPC API.
13+
get_equity_intraday - Get equity intraday data as a DataFrame using Ganymede gRPC API.
14+
get_future_intraday - Get future intraday data as a DataFrame using Ganymede gRPC API.
1315
get_cds_index_option_daily - Get CDS Index option daily data as a DataFrame using Ganymede gRPC API.
1416
get_cds_index_option_by_underlier - Get CDS Index option data filtered by underlier as a DataFrame using Ganymede gRPC API.
1517
"""
@@ -25,9 +27,13 @@
2527
from systemathics.apis.type.shared.v1 import asset_pb2 as asset
2628
from systemathics.apis.type.shared.v1 import constraints_pb2 as constraints
2729
from systemathics.apis.type.shared.v1 import date_interval_pb2 as date_interval
30+
from systemathics.apis.type.shared.v1 import time_interval_pb2 as time_interval
31+
from google.type import timeofday_pb2 as timeofday
2832
import systemathics.apis.type.shared.v1.sampling_pb2 as sampling
2933
import systemathics.apis.type.shared.v1.identifier_pb2 as identifier
3034
import systemathics.apis.services.daily.v1.daily_bars_pb2 as daily_bars
35+
import systemathics.apis.services.intraday.v1.intraday_bars_pb2 as intraday_bars
36+
import systemathics.apis.services.intraday.v1.intraday_bars_pb2_grpc as intraday_bars_service
3137
import systemathics.apis.services.daily.v1.daily_bars_pb2_grpc as daily_bars_service
3238
import systemathics.apis.services.daily.v2.get_daily_pb2 as get_daily
3339
import systemathics.apis.services.daily.v2.get_daily_pb2_grpc as get_daily_service
@@ -1266,6 +1272,216 @@ def _parse_date_for_filtering(date_input):
12661272
print(f"Error: {str(e)}")
12671273
return pd.DataFrame()
12681274

1275+
def get_equity_intraday(ticker, start_date=None, end_date=None, start_time=None, end_time=None, sampling=sampling.SAMPLING_ONE_MINUTE, provider="FirstRateData"):
1276+
"""
1277+
Fetch Equity intraday data from gRPC API for a given ticker and optionally filter by date/time range.
1278+
1279+
Parameters:
1280+
ticker (str): The ticker symbol
1281+
start_date (datetime.date or str, optional): Start date for data retrieval (format: '2025-05-28').
1282+
If None, no start limit is applied
1283+
end_date (datetime.date or str, optional): End date for data retrieval (format: '2025-05-28').
1284+
If None, no end limit is applied
1285+
start_time (datetime.time or str, optional): Start time filter (format: 'HH:MM' or 'HH:MM:SS').
1286+
If None, no start time limit is applied
1287+
end_time (datetime.time or str, optional): End time filter (format: 'HH:MM' or 'HH:MM:SS').
1288+
If None, no end time limit is applied
1289+
sampling (sampling, optional): Sampling period for intraday. Default to one minute.
1290+
provider (str): Data provider, default is "FirstRateData"
1291+
1292+
# Example usage:
1293+
# df = get_equity_intraday('AAPL US Equity') # Get all available data
1294+
# df = get_equity_intraday('AAPL US Equity', start_date='2024-01-01') # From Jan 1, 2024 onwards
1295+
# df = get_equity_intraday('AAPL US Equity', start_date='2024-01-01', end_date='2024-12-31') # Full year 2024
1296+
# df = get_equity_intraday('AAPL US Equity', start_date='2024-01-01', start_time='09:30', end_time='16:00') # With time filter
1297+
1298+
Returns:
1299+
pd.DataFrame: DataFrame with Datetime as index and OHLCV + count/vwap as columns
1300+
"""
1301+
1302+
id = identifier.Identifier(
1303+
ticker=ticker,
1304+
asset_type=asset.AssetType.ASSET_TYPE_EQUITY
1305+
)
1306+
id.provider.value = provider
1307+
1308+
# Build date interval if dates are provided
1309+
date_interval_obj = None
1310+
if start_date is not None or end_date is not None:
1311+
date_interval_kwargs = {}
1312+
if start_date is not None:
1313+
date_interval_kwargs['start_date'] = _parse_date_input(start_date)
1314+
if end_date is not None:
1315+
date_interval_kwargs['end_date'] = _parse_date_input(end_date)
1316+
date_interval_obj = date_interval.DateInterval(**date_interval_kwargs)
1317+
1318+
# Build time interval if times are provided
1319+
time_interval_obj = None
1320+
if start_time is not None or end_time is not None:
1321+
time_interval_kwargs = {}
1322+
if start_time is not None:
1323+
time_interval_kwargs['start_time'] = _parse_time_input(start_time)
1324+
if end_time is not None:
1325+
time_interval_kwargs['end_time'] = _parse_time_input(end_time)
1326+
time_interval_obj = time_interval.TimeInterval(**time_interval_kwargs)
1327+
1328+
request_kwargs = {
1329+
'identifier': id,
1330+
'sampling': sampling,
1331+
}
1332+
if date_interval_obj is not None:
1333+
request_kwargs['date_interval'] = date_interval_obj
1334+
if time_interval_obj is not None:
1335+
request_kwargs['time_interval'] = time_interval_obj
1336+
1337+
request = intraday_bars.IntradayBarsRequest(**request_kwargs)
1338+
1339+
try:
1340+
with channel_helpers.get_grpc_channel() as channel:
1341+
token = token_helpers.get_token()
1342+
service = intraday_bars_service.IntradayBarsServiceStub(channel)
1343+
response = service.IntradayBars(request=request, metadata=[('authorization', token)])
1344+
1345+
if not response or not response.data:
1346+
print("No data received")
1347+
return pd.DataFrame()
1348+
1349+
rows = []
1350+
for b in response.data:
1351+
row = {
1352+
"Datetime": pd.Timestamp(b.time_stamp.seconds, unit='s'),
1353+
"Open": b.open,
1354+
"High": b.high,
1355+
"Low": b.low,
1356+
"Close": b.close,
1357+
"Volume": b.volume,
1358+
"Count": b.count,
1359+
"Vwap": b.vwap,
1360+
}
1361+
rows.append(row)
1362+
1363+
if not rows:
1364+
print("No data received.")
1365+
return pd.DataFrame()
1366+
1367+
return (
1368+
pd.DataFrame(rows)
1369+
.set_index("Datetime")
1370+
.sort_index()
1371+
)
1372+
1373+
except grpc.RpcError as e:
1374+
print(f"gRPC Error [{e.code().name}]: {e.details()}")
1375+
return pd.DataFrame()
1376+
except Exception as e:
1377+
print(f"Error: {e}")
1378+
return pd.DataFrame()
1379+
1380+
def get_future_intraday(ticker, start_date=None, end_date=None, start_time=None, end_time=None, sampling=sampling.SAMPLING_ONE_MINUTE, provider="FirstRateData"):
1381+
"""
1382+
Fetch Future intraday data from gRPC API for a given ticker and optionally filter by date/time range.
1383+
1384+
Parameters:
1385+
ticker (str): The ticker symbol
1386+
start_date (datetime.date or str, optional): Start date for data retrieval (format: '2025-05-28').
1387+
If None, no start limit is applied
1388+
end_date (datetime.date or str, optional): End date for data retrieval (format: '2025-05-28').
1389+
If None, no end limit is applied
1390+
start_time (datetime.time or str, optional): Start time filter (format: 'HH:MM' or 'HH:MM:SS').
1391+
If None, no start time limit is applied
1392+
end_time (datetime.time or str, optional): End time filter (format: 'HH:MM' or 'HH:MM:SS').
1393+
If None, no end time limit is applied
1394+
sampling (sampling, optional): Sampling period for intraday. Default to one minute.
1395+
provider (str): Data provider, default is "FirstRateData"
1396+
1397+
# Example usage:
1398+
# df = get_future_intraday('CL1 Comdty') # Get all available data
1399+
# df = get_future_intraday('CL1 Comdty', start_date='2024-01-01') # From Jan 1, 2024 onwards
1400+
# df = get_future_intraday('CL1 Comdty', start_date='2024-01-01', end_date='2024-12-31') # Full year 2024
1401+
# df = get_future_intraday('CL1 Comdty', start_date='2024-01-01', start_time='09:30', end_time='16:00') # With time filter
1402+
1403+
Returns:
1404+
pd.DataFrame: DataFrame with Datetime as index and OHLCV + count/vwap as columns
1405+
"""
1406+
1407+
id = identifier.Identifier(
1408+
ticker=ticker,
1409+
asset_type=asset.AssetType.ASSET_TYPE_FUTURE
1410+
)
1411+
id.provider.value = provider
1412+
1413+
# Build date interval if dates are provided
1414+
date_interval_obj = None
1415+
if start_date is not None or end_date is not None:
1416+
date_interval_kwargs = {}
1417+
if start_date is not None:
1418+
date_interval_kwargs['start_date'] = _parse_date_input(start_date)
1419+
if end_date is not None:
1420+
date_interval_kwargs['end_date'] = _parse_date_input(end_date)
1421+
date_interval_obj = date_interval.DateInterval(**date_interval_kwargs)
1422+
1423+
# Build time interval if times are provided
1424+
time_interval_obj = None
1425+
if start_time is not None or end_time is not None:
1426+
time_interval_kwargs = {}
1427+
if start_time is not None:
1428+
time_interval_kwargs['start_time'] = _parse_time_input(start_time)
1429+
if end_time is not None:
1430+
time_interval_kwargs['end_time'] = _parse_time_input(end_time)
1431+
time_interval_obj = time_interval.TimeInterval(**time_interval_kwargs)
1432+
1433+
request_kwargs = {
1434+
'identifier': id,
1435+
'sampling': sampling,
1436+
}
1437+
if date_interval_obj is not None:
1438+
request_kwargs['date_interval'] = date_interval_obj
1439+
if time_interval_obj is not None:
1440+
request_kwargs['time_interval'] = time_interval_obj
1441+
1442+
request = intraday_bars.IntradayBarsRequest(**request_kwargs)
1443+
1444+
try:
1445+
with channel_helpers.get_grpc_channel() as channel:
1446+
token = token_helpers.get_token()
1447+
service = intraday_bars_service.IntradayBarsServiceStub(channel)
1448+
response = service.IntradayBars(request=request, metadata=[('authorization', token)])
1449+
1450+
if not response or not response.data:
1451+
print("No data received")
1452+
return pd.DataFrame()
1453+
1454+
rows = []
1455+
for b in response.data:
1456+
row = {
1457+
"Datetime": pd.Timestamp(b.time_stamp.seconds, unit='s'),
1458+
"Open": b.open,
1459+
"High": b.high,
1460+
"Low": b.low,
1461+
"Close": b.close,
1462+
"Volume": b.volume,
1463+
"Count": b.count,
1464+
"Vwap": b.vwap,
1465+
}
1466+
rows.append(row)
1467+
1468+
if not rows:
1469+
print("No data received.")
1470+
return pd.DataFrame()
1471+
1472+
return (
1473+
pd.DataFrame(rows)
1474+
.set_index("Datetime")
1475+
.sort_index()
1476+
)
1477+
1478+
except grpc.RpcError as e:
1479+
print(f"gRPC Error [{e.code().name}]: {e.details()}")
1480+
return pd.DataFrame()
1481+
except Exception as e:
1482+
print(f"Error: {e}")
1483+
return pd.DataFrame()
1484+
12691485

12701486
# Helpers functions
12711487

@@ -1288,6 +1504,31 @@ def _parse_date_input(date_input):
12881504

12891505
raise ValueError(f"Invalid date type: {type(date_input)}")
12901506

1507+
1508+
def _parse_time_input(time_input):
1509+
"""Convert string or datetime.time to Google TimeOfDay protobuf message.
1510+
1511+
Accepts:
1512+
- datetime.time object
1513+
- str in 'HH:MM' or 'HH:MM:SS' format
1514+
"""
1515+
if time_input is None:
1516+
return None
1517+
if isinstance(time_input, datetime):
1518+
t = time_input.time()
1519+
return timeofday.TimeOfDay(hours=t.hour, minutes=t.minute, seconds=t.second)
1520+
from datetime import time as time_type
1521+
if isinstance(time_input, time_type):
1522+
return timeofday.TimeOfDay(hours=time_input.hour, minutes=time_input.minute, seconds=time_input.second)
1523+
if isinstance(time_input, str):
1524+
parts = time_input.split(':')
1525+
h = int(parts[0])
1526+
m = int(parts[1]) if len(parts) > 1 else 0
1527+
s = int(parts[2]) if len(parts) > 2 else 0
1528+
return timeofday.TimeOfDay(hours=h, minutes=m, seconds=s)
1529+
raise ValueError(f"Invalid time type: {type(time_input)}")
1530+
1531+
12911532
def _build_strike_filter(strike) -> "filter.DoubleFilter":
12921533
"""
12931534
Build a DoubleFilter proto from a Python value.

0 commit comments

Comments
 (0)