Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ai hedge fund #33

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions ai-hedge-fund/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# Ignore macOS system files
.DS_Store

# Ignore environment variable files
.env
.env.*

# Ignore build output directories
build/

# Ignore Go debuger and generated files
__debug_bin*
*_generated.go
*.generated.go
2 changes: 2 additions & 0 deletions ai-hedge-fund/agents.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
package main

Check failure on line 1 in ai-hedge-fund/agents.go

View check run for this annotation

Trunk.io / Trunk Check

gofmt

Incorrect formatting, autoformat by running 'trunk fmt'

5 changes: 5 additions & 0 deletions ai-hedge-fund/go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
module ai-hedge-fund

Check failure on line 1 in ai-hedge-fund/go.mod

View check run for this annotation

Trunk.io / Trunk Check

osv-scanner(CVE-2024-34155)

[new] Stack exhaustion in all Parse functions in go/parser. Current version of 'stdlib' is vulnerable: 1.23.0.

Check failure on line 1 in ai-hedge-fund/go.mod

View check run for this annotation

Trunk.io / Trunk Check

osv-scanner(CVE-2024-34156)

[new] Stack exhaustion in Decoder.Decode in encoding/gob. Current version of 'stdlib' is vulnerable: 1.23.0.

Check failure on line 1 in ai-hedge-fund/go.mod

View check run for this annotation

Trunk.io / Trunk Check

osv-scanner(CVE-2024-34158)

[new] Stack exhaustion in Parse in go/build/constraint. Current version of 'stdlib' is vulnerable: 1.23.0.

go 1.23.0

require github.com/hypermodeinc/modus/sdk/go v0.15.0
4 changes: 4 additions & 0 deletions ai-hedge-fund/go.sum
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
github.com/hypermodeinc/modus/sdk/go v0.14.3 h1:7lXJvLchg2T0iT3dWwVJlua1uODVoRN5BJIEKzzZ2K8=
github.com/hypermodeinc/modus/sdk/go v0.14.3/go.mod h1:VDL2kAYHQtNEr7lxPynbchZ6HizLSSQ9cG4LrDnq3Vg=
github.com/hypermodeinc/modus/sdk/go v0.15.0 h1:xRD4swlxdug4fVVKzY2FQKGUTKK2qLSDb0k/wqDDTOw=
github.com/hypermodeinc/modus/sdk/go v0.15.0/go.mod h1:Tgh2CfZztlmsAi5DAF1s2LhoARF6P61huICuuAd7hvY=
19 changes: 19 additions & 0 deletions ai-hedge-fund/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package main

import (
"fmt"

_ "github.com/hypermodeinc/modus/sdk/go"
)

func SayHello(name *string) string {

var s string
if name == nil {
s = "World"
} else {
s = *name
}

return fmt.Sprintf("Hello, %s!", s)
}
35 changes: 35 additions & 0 deletions ai-hedge-fund/modus.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
{
"$schema": "https://schema.hypermode.com/modus.json",
"endpoints": {
"default": {
"type": "graphql",
"path": "/graphql",
"auth": "bearer-token"
}
},
"models": {
"openai": {
"sourceModel": "gpt-4o",
"connection": "openai",
"path": "v1/chat/completions"
}
},
"connections": {
// This defines the OpenAI host, which is used by the model above.
// The {{API_KEY}} will be replaced by the secret's value at run time.
"openai": {
"type": "http",
"baseUrl": "https://api.openai.com/",
"headers": {
"Authorization": "Bearer {{API_KEY}}"
}
},
"financial-datasets": {
"type": "http",
"baseUrl": "https://api.financialdatasets.ai/financial-metrics/",
"headers": {
"X-API-KEY": "{{API_KEY}}"
}
}
}
}
166 changes: 166 additions & 0 deletions ai-hedge-fund/tools.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,166 @@
package main

Check failure on line 1 in ai-hedge-fund/tools.go

View check run for this annotation

Trunk.io / Trunk Check

gofmt

Incorrect formatting, autoformat by running 'trunk fmt'

import (
"encoding/json"
"fmt"

_ "github.com/hypermodeinc/modus/sdk/go"
"github.com/hypermodeinc/modus/sdk/go/pkg/http"
)

func GetFinancialMetrics(
ticker string,
reportPeriod string,
period *string,
limit *int,
) ([]FinancialMetrics, error) {
if period == nil {
defaultPeriod := "ttm"
period = &defaultPeriod
}
if limit == nil {
defaultLimit := 1
limit = &defaultLimit
}
url := fmt.Sprintf("https://api.financialdatasets.ai/financial-metrics/?ticker=%s&report_period_lte=%s&limit=%d&period=%s",
ticker, reportPeriod, *limit, *period)
req := http.NewRequest(url, &http.RequestOptions{
Method: "GET",
})

res, err := http.Fetch(req)
if err != nil {
return nil, err
}

var fmresponse FinancialMetricsAPIResponse

err = json.Unmarshal(res.Body, &fmresponse)
if err != nil {
return nil, err
}

fmt.Println(res.Body)
return fmresponse.FinancialMetrics, nil
}

func GetInsiderTrades(
ticker string,
endDate string,
limit *int,
) ([]InsiderTrade, error) {
if limit == nil {
defaultLimit := 5
limit = &defaultLimit
}

url := fmt.Sprintf("https://api.financialdatasets.ai/insider-trades/?ticker=%s&filing_date_lte=%s&limit=%d",
ticker, endDate, *limit)

req := http.NewRequest(url, &http.RequestOptions{
Method: "GET",
})

res, err := http.Fetch(req)
if err != nil {
return nil, err
}

var response InsiderTradesResponse
err = json.Unmarshal(res.Body, &response)
if err != nil {
return nil, err
}

return response.InsiderTrades, nil
}

func SearchLineItems(
ticker []string,
lineItems []string,
period *string,
limit *int,
) ([]SearchResult, error) {
if period == nil {
defaultPeriod := "ttm"
period = &defaultPeriod
}
if limit == nil {
defaultLimit := 1
limit = &defaultLimit
}

url := "https://api.financialdatasets.ai/financials/search/line-items"

body := SearchLineItemsRequest{
Tickers: ticker,
LineItems: lineItems,
Period: *period,
Limit: *limit,
}

req := http.NewRequest(url, &http.RequestOptions{
Method: "POST",
Body: body,
})

res, err := http.Fetch(req)
if err != nil {
return nil, err
}

var response SearchLineItemsResponse
err = json.Unmarshal(res.Body, &response)
if err != nil {
return nil, err
}

return response.SearchResults, nil
}

func GetMarketCap(ticker string) (*CompanyFacts, error) {
url := fmt.Sprintf("https://api.financialdatasets.ai/company/facts?ticker=%s", ticker)

req := http.NewRequest(url, &http.RequestOptions{
Method: "GET",
})

res, err := http.Fetch(req)
if err != nil {
return nil, err
}

var response CompanyFactsResponse
err = json.Unmarshal(res.Body, &response)
if err != nil {
return nil, err
}

return &response.CompanyFacts, nil
}

func GetPrices(
ticker string,
startDate string,
endDate string,
) ([]Price, error) {
url := fmt.Sprintf("https://api.financialdatasets.ai/prices/?ticker=%s&interval=day&interval_multiplier=1&start_date=%s&end_date=%s",
ticker, startDate, endDate)

req := http.NewRequest(url, &http.RequestOptions{
Method: "GET",
})

res, err := http.Fetch(req)
if err != nil {
return nil, err
}

var response PricesResponse
err = json.Unmarshal(res.Body, &response)
if err != nil {
return nil, err
}

return response.Prices, nil
}
144 changes: 144 additions & 0 deletions ai-hedge-fund/types.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
package main

Check failure on line 1 in ai-hedge-fund/types.go

View check run for this annotation

Trunk.io / Trunk Check

gofmt

Incorrect formatting, autoformat by running 'trunk fmt'

import "encoding/json"

type FinancialMetricsAPIResponse struct {
FinancialMetrics []FinancialMetrics `json:"financial_metrics"`
}

type FinancialMetrics struct {
Ticker string `json:"ticker"`
MarketCap float64 `json:"market_cap"`
EnterpriseValue float64 `json:"enterprise_value"`
PriceToEarningsRatio float64 `json:"price_to_earnings_ratio"`
PriceToBookRatio float64 `json:"price_to_book_ratio"`
PriceToSalesRatio float64 `json:"price_to_sales_ratio"`
EnterpriseValueToEbitdaRatio float64 `json:"enterprise_value_to_ebitda_ratio"`
EnterpriseValueToRevenueRatio float64 `json:"enterprise_value_to_revenue_ratio"`
GrossMargin float64 `json:"gross_margin"`
OperatingMargin float64 `json:"operating_margin"`
NetMargin float64 `json:"net_margin"`
ReturnOnEquity float64 `json:"return_on_equity"`
ReturnOnAssets float64 `json:"return_on_assets"`
ReturnOnInvestedCapital float64 `json:"return_on_invested_capital"`
AssetTurnover float64 `json:"asset_turnover"`
InventoryTurnover float64 `json:"inventory_turnover"`
CurrentRatio float64 `json:"current_ratio"`
QuickRatio float64 `json:"quick_ratio"`
CashRatio float64 `json:"cash_ratio"`
DebtToEquity float64 `json:"debt_to_equity"`
DebtToAssets float64 `json:"debt_to_assets"`
RevenueGrowth float64 `json:"revenue_growth"`
EarningsGrowth float64 `json:"earnings_growth"`
BookValueGrowth float64 `json:"book_value_growth"`
PayoutRatio float64 `json:"payout_ratio"`
EarningsPerShare float64 `json:"earnings_per_share"`
BookValuePerShare float64 `json:"book_value_per_share"`
FreeCashFlowPerShare float64 `json:"free_cash_flow_per_share"`
}

// Insider Trades
type InsiderTradesResponse struct {
InsiderTrades []InsiderTrade `json:"insider_trades"`
}

type InsiderTrade struct {
Ticker string `json:"ticker"`
Issuer string `json:"issuer"`
Name string `json:"name"`
Title string `json:"title"`
IsBoardDirector bool `json:"is_board_director"`
TransactionDate string `json:"transaction_date"`
TransactionShares float64 `json:"transaction_shares"`
TransactionPricePerShare float64 `json:"transaction_price_per_share"`
TransactionValue float64 `json:"transaction_value"`
SharesOwnedBeforeTransaction float64 `json:"shares_owned_before_transaction"`
SharesOwnedAfterTransaction float64 `json:"shares_owned_after_transaction"`
SecurityTitle string `json:"security_title"`
FilingDate string `json:"filing_date"`
}

// Company Facts
type CompanyFactsResponse struct {
CompanyFacts CompanyFacts `json:"company_facts"`
}

type CompanyFacts struct {
Ticker string `json:"ticker"`
Name string `json:"name"`
CIK string `json:"cik"`
MarketCap float64 `json:"market_cap"`
WeightedAverageShares float64 `json:"weighted_average_shares"`
NumberOfEmployees float64 `json:"number_of_employees"`
SICCode string `json:"sic_code"`
SICDescription string `json:"sic_description"`
WebsiteURL string `json:"website_url"`
ListingDate string `json:"listing_date"`
IsActive bool `json:"is_active"`
}

// Prices
type PricesResponse struct {
Prices []Price `json:"prices"`
}

type Price struct {
Open float64 `json:"open"`
Close float64 `json:"close"`
High float64 `json:"high"`
Low float64 `json:"low"`
Volume int64 `json:"volume"`
Time string `json:"time"`
}

type SearchLineItemsRequest struct {
Period string `json:"period"`
Tickers []string `json:"tickers"`
Limit int `json:"limit"`
LineItems []string `json:"line_items"`
}

type SearchLineItemsResponse struct {
SearchResults []SearchResult `json:"search_results"`
}

type SearchResult struct {
Ticker string `json:"ticker"`
ReportPeriod string `json:"report_period"`
Values map[string]float64 `json:"-"` // Will be populated from the dynamic fields
}

// UnmarshalJSON implements custom unmarshaling for SearchResult
func (sr *SearchResult) unmarshalJSON(data []byte) error {

Check failure on line 112 in ai-hedge-fund/types.go

View check run for this annotation

Trunk.io / Trunk Check

golangci-lint(unused)

[new] func `(*SearchResult).unmarshalJSON` is unused
// First create a map to hold all JSON data
var rawMap map[string]interface{}
if err := json.Unmarshal(data, &rawMap); err != nil {
return err
}

// Initialize the Values map
sr.Values = make(map[string]float64)

// Extract known fields
if ticker, ok := rawMap["ticker"].(string); ok {
sr.Ticker = ticker
}
if period, ok := rawMap["report_period"].(string); ok {
sr.ReportPeriod = period
}

// Move all numeric values to the Values map
for key, value := range rawMap {
if key != "ticker" && key != "report_period" {
// Try to convert the value to float64
switch v := value.(type) {
case float64:
sr.Values[key] = v
case int:
sr.Values[key] = float64(v)
}
}
}

return nil
}
Loading