Dmitry Beresnev
commited on
Commit
·
59845f6
1
Parent(s):
13212b8
fix the requests to the FMP API
Browse files
src/api/insiders/insider_trading_aggregator.py
CHANGED
|
@@ -111,68 +111,75 @@ class InsiderTradingAggregator:
|
|
| 111 |
|
| 112 |
async def get_fmp_insider_trades(self, session: aiohttp.ClientSession,
|
| 113 |
symbol: str, limit: int = 100, filter_days: int = 30) -> List[InsiderTrade]:
|
| 114 |
-
"""
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 115 |
all_trades = []
|
| 116 |
-
|
| 117 |
-
|
| 118 |
-
|
| 119 |
-
|
| 120 |
-
|
| 121 |
-
|
| 122 |
-
|
| 123 |
-
|
| 124 |
-
|
| 125 |
-
|
| 126 |
-
|
| 127 |
-
|
| 128 |
-
|
| 129 |
-
|
| 130 |
-
|
| 131 |
-
|
| 132 |
-
|
| 133 |
-
|
| 134 |
-
|
| 135 |
-
|
| 136 |
-
|
| 137 |
-
|
| 138 |
-
|
| 139 |
-
|
| 140 |
-
|
| 141 |
-
|
| 142 |
-
|
| 143 |
-
|
| 144 |
-
|
| 145 |
-
|
| 146 |
-
|
| 147 |
-
|
| 148 |
-
|
| 149 |
-
|
| 150 |
-
|
| 151 |
-
|
| 152 |
-
|
| 153 |
-
|
| 154 |
-
|
| 155 |
-
|
| 156 |
-
|
| 157 |
-
|
| 158 |
-
|
| 159 |
-
|
| 160 |
-
|
| 161 |
-
|
| 162 |
-
|
| 163 |
-
|
| 164 |
-
|
| 165 |
-
|
| 166 |
-
|
| 167 |
-
|
| 168 |
-
|
| 169 |
-
|
| 170 |
-
|
| 171 |
-
|
| 172 |
-
|
| 173 |
-
|
| 174 |
-
|
| 175 |
-
logger.info(f"Retrieved {len(all_trades)} recent trades from FMP for {symbol}.")
|
| 176 |
return all_trades
|
| 177 |
|
| 178 |
async def get_sec_api_insider_trades(self, session: aiohttp.ClientSession,
|
|
|
|
| 111 |
|
| 112 |
async def get_fmp_insider_trades(self, session: aiohttp.ClientSession,
|
| 113 |
symbol: str, limit: int = 100, filter_days: int = 30) -> List[InsiderTrade]:
|
| 114 |
+
"""
|
| 115 |
+
Get insider trades from Financial Modeling Prep API
|
| 116 |
+
Get insider trades from FMP by iterating day-by-day for a specific period.
|
| 117 |
+
NOTE: This method is inefficient and makes many API calls.
|
| 118 |
+
"""
|
| 119 |
+
if filter_days > 14:
|
| 120 |
+
logger.warning(f"FMP date range capped at 14 days. Reducing from {filter_days} to 14.")
|
| 121 |
+
filter_days = 14
|
| 122 |
+
|
| 123 |
all_trades = []
|
| 124 |
+
today = datetime.now()
|
| 125 |
+
date_range = [today - timedelta(days=i) for i in range(filter_days)]
|
| 126 |
+
|
| 127 |
+
# Outer Loop: Iterate through each day in the specified range.
|
| 128 |
+
for single_date in date_range:
|
| 129 |
+
page = 0
|
| 130 |
+
date_str = single_date.strftime('%Y-%m-%d')
|
| 131 |
+
|
| 132 |
+
# Inner Loop: Handle pagination for the current day.
|
| 133 |
+
while True:
|
| 134 |
+
endpoint = "insider-trading"
|
| 135 |
+
params = {
|
| 136 |
+
'symbol': symbol,
|
| 137 |
+
'date': date_str,
|
| 138 |
+
'page': page,
|
| 139 |
+
'limit': limit
|
| 140 |
+
}
|
| 141 |
+
|
| 142 |
+
logger.info(f"Requesting FMP data for {symbol} on {date_str}, page {page}...")
|
| 143 |
+
data = await self._make_request(session, 'fmp', endpoint, params)
|
| 144 |
+
|
| 145 |
+
# If no data is returned for this page, we're done with this date.
|
| 146 |
+
if not data:
|
| 147 |
+
break
|
| 148 |
+
|
| 149 |
+
for trade in data:
|
| 150 |
+
try:
|
| 151 |
+
disposition = (trade.get('acquistionOrDisposition') or '').upper()
|
| 152 |
+
trans_type = TransactionType.BUY.value if disposition == 'A' else TransactionType.SELL.value
|
| 153 |
+
|
| 154 |
+
shares = int(trade.get('securitiesTransacted', 0) or 0)
|
| 155 |
+
price = float(trade.get('price', 0) or 0)
|
| 156 |
+
|
| 157 |
+
insider_trade = InsiderTrade(
|
| 158 |
+
symbol=trade.get('symbol', ''),
|
| 159 |
+
company_name=trade.get('companyName', ''),
|
| 160 |
+
insider_name=trade.get('reportingName', ''),
|
| 161 |
+
position=trade.get('typeOfOwner', ''),
|
| 162 |
+
transaction_date=trade.get('transactionDate', ''),
|
| 163 |
+
transaction_type=trans_type,
|
| 164 |
+
shares=shares,
|
| 165 |
+
price=price,
|
| 166 |
+
value=float(shares * price),
|
| 167 |
+
form_type=trade.get('formType', ''),
|
| 168 |
+
source='FMP',
|
| 169 |
+
filing_date=trade.get('filingDate', ''),
|
| 170 |
+
ownership_type=trade.get('directOrIndirectOwnership', '')
|
| 171 |
+
)
|
| 172 |
+
all_trades.append(insider_trade)
|
| 173 |
+
except (ValueError, TypeError) as e:
|
| 174 |
+
logger.warning(f"Error parsing FMP trade data for {symbol}: {e} -> {trade}")
|
| 175 |
+
continue
|
| 176 |
+
|
| 177 |
+
# Increment the page to fetch the next set of results for the same day.
|
| 178 |
+
page += 1
|
| 179 |
+
await asyncio.sleep(0.2) # Courteous delay
|
| 180 |
+
|
| 181 |
+
logger.info(
|
| 182 |
+
f"Retrieved {len(all_trades)} trades from FMP for {symbol} by iterating through {len(date_range)} days.")
|
|
|
|
| 183 |
return all_trades
|
| 184 |
|
| 185 |
async def get_sec_api_insider_trades(self, session: aiohttp.ClientSession,
|