File size: 6,572 Bytes
2b26c07
92fdd4b
9b5b26a
 
c19d193
f906687
514d93c
6aae614
8fe992b
9b5b26a
 
93ed848
966940f
93ed848
 
9b5b26a
93ed848
9b5b26a
93ed848
 
 
 
966940f
93ed848
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
8c01ffb
cd230b1
514d93c
966940f
514d93c
966940f
 
514d93c
 
 
0ea0b34
514d93c
 
 
 
 
8c01ffb
bd1afaf
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
7b428a4
514d93c
7b428a4
514d93c
7b428a4
 
514d93c
 
7b428a4
 
514d93c
7b428a4
514d93c
 
7b428a4
514d93c
 
 
 
0ea0b34
514d93c
 
 
7b428a4
514d93c
 
 
 
dd76302
0ea0b34
514d93c
 
 
 
7b428a4
514d93c
 
 
7b428a4
514d93c
 
 
 
dd76302
7b428a4
514d93c
 
 
 
7b428a4
514d93c
 
 
7b428a4
514d93c
 
 
 
 
7b428a4
514d93c
 
 
 
7b428a4
514d93c
 
 
7b428a4
514d93c
 
 
 
 
0ea0b34
 
514d93c
0ea0b34
514d93c
0ea0b34
 
514d93c
 
0ea0b34
 
514d93c
 
 
dd76302
 
514d93c
 
2b26c07
7d19447
6aae614
ae7a494
 
 
 
e121372
bf6d34c
 
29ec968
fe328e0
13d500a
8c01ffb
9b5b26a
 
8c01ffb
861422e
 
9b5b26a
8c01ffb
8fe992b
fe4e709
8c01ffb
 
 
 
 
 
861422e
8fe992b
 
8c01ffb
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
from smolagents import CodeAgent, DuckDuckGoSearchTool, HfApiModel, load_tool, tool
from datetime import datetime
import requests
import pytz
import yaml
import yfinance as yf
from typing import Tuple, Dict, Any
from tools.final_answer import FinalAnswerTool

from Gradio_UI import GradioUI

def _get_atm_option_data(ticker: str, dte: int):
    """
    Internal helper to fetch underlying price, selected expiration,
    ATM strike, ATM call row, and ATM put row.
    """
    stock = yf.Ticker(ticker)

    hist = stock.history(period="1d")
    if hist.empty:
        raise ValueError(f"No price data found for {ticker}.")
    underlying_price = float(hist["Close"].iloc[-1])

    expirations = stock.options
    if not expirations:
        raise ValueError(f"No options data available for {ticker}.")

    exp_dates = [datetime.strptime(exp, "%Y-%m-%d") for exp in expirations]
    today = datetime.now()
    dtes = [(exp - today).days for exp in exp_dates]

    target_idx = min(range(len(dtes)), key=lambda i: abs(dtes[i] - dte))
    expiration = expirations[target_idx]

    opt_chain = stock.option_chain(expiration)
    calls = opt_chain.calls
    puts = opt_chain.puts

    if calls.empty or puts.empty:
        raise ValueError(f"Options chain incomplete for {ticker} on {expiration}.")

    calls["diff"] = (calls["strike"] - underlying_price).abs()
    atm_strike = float(calls.sort_values("diff").iloc[0]["strike"])

    call_row = calls[calls["strike"] == atm_strike].iloc[0]
    put_row = puts[puts["strike"] == atm_strike].iloc[0]

    return underlying_price, expiration, atm_strike, call_row, put_row

@tool
def yf_underlying_price(ticker: str, dte: int = 0) -> float:
    """
    Get the current underlying stock price for the given ticker.

    Args:
        ticker (str): The stock ticker symbol, e.g., AAPL.
        dte (int): Days-to-expiration used to select the option chain.
            Defaults to 0 (nearest expiration).

    Returns:
        float: The current underlying stock price.
    """
    underlying_price, _, _, _, _ = _get_atm_option_data(ticker, dte)
    return underlying_price

@tool
def yf_selected_expiration(ticker: str, dte: int = 0) -> str:
    """
    Return the option expiration date selected for the given stock ticker and
    desired days-to-expiration (DTE). The expiration chosen is the one whose
    days-to-expiration is closest to the requested DTE.

    Args:
        ticker (str): The stock ticker symbol, e.g., AAPL.
        dte (int): Desired days-to-expiration. A value of 0 selects the nearest
            available expiration. Defaults to 0.

    Returns:
        str: The selected expiration date in YYYY-MM-DD format.
    """
    _, expiration, _, _, _ = _get_atm_option_data(ticker, dte)
    return expiration

@tool
def yf_atm_strike(ticker: str, dte: int = 0) -> float:
    """
    Get the at-the-money (ATM) strike price for the given ticker.

    Args:
        ticker (str): The stock ticker symbol.
        dte (int): Desired days-to-expiration. Defaults to 0.

    Returns:
        float: The ATM strike price.
    """
    _, _, atm_strike, _, _ = _get_atm_option_data(ticker, dte)
    return atm_strike

@tool
def yf_atm_call_price(ticker: str, dte: int = 0) -> float:
    """
    Get the last traded price of the ATM call option.

    Args:
        ticker (str): The stock ticker symbol.
        dte (int): Desired days-to-expiration. Defaults to 0.

    Returns:
        float: The ATM call option price.
    """
    _, _, _, call_row, _ = _get_atm_option_data(ticker, dte)
    return float(call_row.get("ask", 0.0))

@tool
def yf_atm_put_price(ticker: str, dte: int = 0) -> float:
    """
    Get the last traded price of the ATM put option.

    Args:
        ticker (str): The stock ticker symbol.
        dte (int): Desired days-to-expiration. Defaults to 0.

    Returns:
        float: The ATM put option price.
    """
    _, _, _, _, put_row = _get_atm_option_data(ticker, dte)
    return float(put_row.get("ask", 0.0))

@tool
def yf_atm_call_iv(ticker: str, dte: int = 0) -> float:
    """
    Get the implied volatility (IV) of the ATM call option.

    Args:
        ticker (str): The stock ticker symbol.
        dte (int): Desired days-to-expiration. Defaults to 0.

    Returns:
        float: The implied volatility of the ATM call option.
    """
    _, _, _, call_row, _ = _get_atm_option_data(ticker, dte)
    return float(call_row.get("impliedVolatility", 0.0))

@tool
def yf_atm_put_iv(ticker: str, dte: int = 0) -> float:
    """
    Get the implied volatility (IV) of the ATM put option.

    Args:
        ticker (str): The stock ticker symbol.
        dte (int): Desired days-to-expiration. Defaults to 0.

    Returns:
        float: The implied volatility of the ATM put option.
    """
    _, _, _, _, put_row = _get_atm_option_data(ticker, dte)
    return float(put_row.get("impliedVolatility", 0.0))

@tool
def yf_atm_straddle_price(ticker: str, dte: int = 0) -> float:
    """
    Calculate the price of the ATM straddle (call + put).

    Args:
        ticker (str): The stock ticker symbol.
        dte (int): Desired days-to-expiration. Defaults to 0.

    Returns:
        float: The total ATM straddle price.
    """
    _, _, _, call_row, put_row = _get_atm_option_data(ticker, dte)
    call_price = float(call_row.get("ask", 0.0))
    put_price = float(put_row.get("ask", 0.0))
    return call_price + put_price

ddgs = DuckDuckGoSearchTool();

final_answer = FinalAnswerTool()

# If the agent does not answer, the model is overloaded, please use another model or the following Hugging Face Endpoint that also contains qwen2.5 coder:
# model_id='https://pflgm2locj2t89co.us-east-1.aws.endpoints.huggingface.cloud' 

model = HfApiModel(
max_tokens=2096,
temperature=0.5,
model_id='Qwen/Qwen2.5-Coder-32B-Instruct',# it is possible that this model may be overloaded
custom_role_conversions=None,
)

# Import tool from Hub
image_generation_tool = load_tool("agents-course/text-to-image", trust_remote_code=True)

with open("prompts.yaml", 'r') as stream:
    prompt_templates = yaml.safe_load(stream)
    
agent = CodeAgent(
    model=model,
    tools=[final_answer, ddgs, yf_underlying_price, yf_selected_expiration, yf_atm_strike, yf_atm_call_price, yf_atm_put_price, yf_atm_call_iv, yf_atm_put_iv, yf_atm_straddle_price], ## add your tools here (don't remove final answer)
    max_steps=6,
    verbosity_level=1,
    grammar=None,
    planning_interval=None,
    name=None,
    description=None,
    prompt_templates=prompt_templates
)

GradioUI(agent).launch()