-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathAlpacaAPI.py
232 lines (197 loc) · 8.01 KB
/
AlpacaAPI.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
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
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
from collections import defaultdict
import alpaca_trade_api as tradeapi
from alpaca_trade_api.rest import TimeFrame, REST
from datetime import date, timedelta
import logging
import pandas as pd
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger("AlpacaAPI")#="TradingBot"
logger.setLevel(logging.INFO)
class AlpacaAPI:
def __init__(self, api_key, secret_key, base_url="https://paper-api.alpaca.markets"):
"""
Alpaca API wrapper for trading and data fetching using alpaca-trade-api.
"""
self.api = tradeapi.REST(api_key, secret_key, base_url)
self.positions = {} # Track current stocks
self.checkbook = {} # Track buy prices
self.sold_book = {} # History sold symbols
from collections import defaultdict
def populate_checkbook(self):
"""
Fetch past buy orders and populate the checkbook with all buy prices for each symbol.
"""
try:
# Initialize checkbook as a defaultdict of lists
if not isinstance(self.checkbook, defaultdict):
self.checkbook = defaultdict(list)
# Fetch all closed orders
orders = self.api.list_orders(status='filled', limit=500)
for order in orders:
# Only process buy orders
if order.side == 'buy' and order.filled_avg_price:
symbol = order.symbol
buy_price = float(order.filled_avg_price)
# Append buy price to the list for the symbol
if buy_price not in self.checkbook[symbol]:
self.checkbook[symbol].append(buy_price)
logging.info(f"Added {symbol} to checkbook with buy price {buy_price}")
except Exception as e:
logging.error(f"Error populating checkbook: {e}")
def populate_sold_book(self):
"""
Populate sold_book with past sell transactions.
"""
transactions = self.fetch_all_transactions()
for txn in transactions:
if txn['side'] == 'sell' and txn['price'] is not None:
self.sold_book[txn['symbol']] = {
'sell_price': txn['price'],
'timestamp': txn['timestamp']
}
logging.info(f"Added {txn['symbol']} to sold_book with price {txn['price']}")
def fetch_positions(self):
"""
Fetch current positions from Alpaca API, including real-time market prices.
"""
try:
# Fetch current positions
positions = self.api.list_positions()
# Store positions with additional real-time price info
self.positions = {}
for pos in positions:
symbol = pos.symbol
qty = int(pos.qty)
current_price = float(pos.current_price)
# Fetch the latest market price (real-time data)
try:
latest_trade = self.api.get_latest_trade(symbol=symbol, feed='iex')
market_price = float(latest_trade.price) # Real-time price
except Exception as e:
market_price = current_price # Fallback to Alpaca's current_price
logger.warning(f"Error fetching real-time price for {symbol}: {e}")
self.positions[symbol] = {
'qty': int(qty),
'current_price': float(current_price), # From Alpaca position data
'market_price': float(market_price) # Real-time market price
}
self.populate_checkbook()
return self.positions
except tradeapi.rest.APIError as e:
raise Exception(f"Error fetching positions: {e}")
def place_order(self, symbol, qty, side="buy", order_type="market", time_in_force="gtc"):
"""
Place an order via Alpaca API.
"""
try:
order = self.api.submit_order(
symbol=symbol,
qty=qty,
side=side,
type=order_type,
time_in_force=time_in_force,
)
print(f"Order placed: {order}")
except tradeapi.rest.APIError as e:
raise Exception(f"Error placing order: {e}")
def calculate_portfolio_value(self):
"""
Calculate the total portfolio value.
"""
try:
account = self.api.get_account()
return float(account.portfolio_value)
except tradeapi.rest.APIError as e:
raise Exception(f"Error fetching portfolio value: {e}")
def fetch_historical_data(self, symbol, start_date):
try:
end_date = (date.today() - timedelta(days=1)).strftime("%Y-%m-%d")
bars = self.api.get_bars(
symbol,
TimeFrame.Day,
start=start_date,
end=end_date,
adjustment='all'
).df
#logging.info(f"Data retrieved: {bars.tail(3)}")
return bars
except Exception as e:
logger.error(f"Error fetching historical data for {symbol}: {e}")
raise
def fetch_raw_data(self, symbol):
"""
Fetches the latest bar data for a specific symbol.
Returns a dictionary with relevant fields like open, high, low, close, volume.
"""
try:
latest_bar = self.api.get_latest_bar(symbol=symbol, feed='iex') # Fetch data
# Format the data as a dictionary
return {
'open': latest_bar.o,
'high': latest_bar.h,
'low': latest_bar.l,
'close': latest_bar.c,
'volume': latest_bar.v,
'timestamp': latest_bar.t
}
except Exception as e:
logger.error(f"Error fetching raw data for {symbol}: {e}")
return None
def fetch_all_transactions(self, status='filled', limit=200):
"""
Fetch all filled transactions from Alpaca.
"""
try:
orders = self.api.list_orders(status=status, limit=limit)
transaction_data = []
for order in orders:
transaction_data.append({
'symbol': order.symbol,
'side': order.side,
'price': float(order.filled_avg_price) if order.filled_avg_price else None,
'qty': int(order.filled_qty) if order.filled_qty else None,
'timestamp': order.filled_at
})
return transaction_data
except Exception as e:
logger.error(f"Error fetching transactions: {e}")
return []
def is_market_open(self):
"""
Check if the market is currently open.
"""
try:
clock = self.api.get_clock()
return clock.is_open
except tradeapi.rest.APIError as e:
raise Exception(f"Error checking market status: {e}")
def get_account_info(self):
"""
Retrieve account details.
"""
try:
return self.api.get_account()
except tradeapi.rest.APIError as e:
raise Exception(f"Error fetching account information: {e}")
# Example usage
if __name__ == "__main__":
from config import ALPACA_API_KEY, ALPACA_SECRET_KEY
alpaca = AlpacaAPI(ALPACA_API_KEY, ALPACA_SECRET_KEY)
# # Fetch positions
# positions = alpaca.fetch_positions()
# print("Positions:", positions)
# # Place an order
# try:
# alpaca.place_order("RGTI", 1, side="buy")
# except Exception as e:
# print(f"Error placing order: {e}")
# Fetch historical data
# data = alpaca.fetch_historical_data("RGTI", "2024-11-01")
# print(data)
# print("\n\n")
# raw_data = alpaca.api.get_latest_bars("RGTI")
# print(raw_data)
# # Check if market is open
# is_open = alpaca.is_market_open()
# print("\nMarket is open:", is_open)
# print("\n", alpaca.calculate_portfolio_value())