Skip to content
Open
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
18 changes: 14 additions & 4 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,9 +1,19 @@
FROM alpine:3
FROM golang:1.20-alpine

# Set environment variable for terminal colors
ENV TERM=xterm-256color

COPY ticker /ticker
# Set the working directory
WORKDIR /ticker

VOLUME ["/.ticker.yaml"]
# Download dependencies (this happens once, not every build)
COPY go.mod ./
COPY go.sum ./
RUN go mod download

# Expose the volume for configuration file
VOLUME ["/ticker/.ticker.yaml"]

# Default entrypoint
CMD ["sh"]

ENTRYPOINT ["/ticker"]
72 changes: 65 additions & 7 deletions internal/asset/asset.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@
"strings"

c "github.com/achannarasappa/ticker/v5/internal/common"
"fmt"

Check failure on line 7 in internal/asset/asset.go

View workflow job for this annotation

GitHub Actions / lint

"fmt" imported and not used (typecheck)
"github.com/achannarasappa/ticker/v4/internal/currency"

Check failure on line 8 in internal/asset/asset.go

View workflow job for this annotation

GitHub Actions / coverage

no required module provides package github.com/achannarasappa/ticker/v4/internal/currency; to add it:

Check failure on line 8 in internal/asset/asset.go

View workflow job for this annotation

GitHub Actions / test (1.23.x, ubuntu-latest)

no required module provides package github.com/achannarasappa/ticker/v4/internal/currency; to add it:

Check failure on line 8 in internal/asset/asset.go

View workflow job for this annotation

GitHub Actions / test (1.23.x, macos-latest)

no required module provides package github.com/achannarasappa/ticker/v4/internal/currency; to add it:
// "github.com/achannarasappa/ticker/internal/alert"
)

// AggregatedLot represents a cost basis lot of an asset grouped by symbol
Expand All @@ -12,6 +15,7 @@
Cost float64
Quantity float64
OrderIndex int
TargetPrice *float64
}

// HoldingSummary represents a summary of all asset holdings at a point in time
Expand Down Expand Up @@ -73,6 +77,9 @@

assets = updateHoldingWeights(assets, holdingSummary)

// Evaluate assets and trigger alerts if necessary
processAssets(assets)

return assets, holdingSummary

}
Expand Down Expand Up @@ -118,20 +125,35 @@

}

func getHoldingFromAssetQuote(assetQuote c.AssetQuote, lotsBySymbol map[string]AggregatedLot, currencyRateByUse currencyRateByUse) c.Holding {
func processAssets(assets []c.Asset) {
for _, asset := range assets {
if asset.Holding.TargetPrice == nil {
continue // No target price, so no alert is required
}

currentPrice := asset.QuotePrice.Price
targetPrice := *asset.Holding.TargetPrice

// Trigger an alert if the current price exceeds the target price
if currentPrice >= targetPrice {
// fmt.Printf("📢 Alert: %s has reached the target price! Current: $%.2f, Target: $%.2f\n", asset.Symbol, currentPrice, targetPrice)
}
}
}

func getHoldingFromAssetQuote(assetQuote c.AssetQuote, lotsBySymbol map[string]AggregatedLot, currencyRateByUse currency.CurrencyRateByUse) c.Holding {
if aggregatedLot, ok := lotsBySymbol[assetQuote.Symbol]; ok {
value := aggregatedLot.Quantity * assetQuote.QuotePrice.Price * currencyRateByUse.QuotePrice
cost := aggregatedLot.Cost * currencyRateByUse.PositionCost
totalChangeAmount := value - cost
totalChangePercent := (totalChangeAmount / cost) * 100

return c.Holding{
Value: value,
Cost: cost,
Quantity: aggregatedLot.Quantity,
UnitValue: value / aggregatedLot.Quantity,
UnitCost: cost / aggregatedLot.Quantity,
Value: value,
Cost: cost,
Quantity: aggregatedLot.Quantity,
UnitValue: value / aggregatedLot.Quantity,
UnitCost: cost / aggregatedLot.Quantity,
DayChange: c.HoldingChange{
Amount: assetQuote.QuotePrice.Change * aggregatedLot.Quantity * currencyRateByUse.QuotePrice,
Percent: assetQuote.QuotePrice.ChangePercent,
Expand All @@ -140,14 +162,49 @@
Amount: totalChangeAmount,
Percent: totalChangePercent,
},
Weight: 0,
Weight: 0,
TargetPrice: aggregatedLot.TargetPrice, // Assign TargetPrice from AggregatedLot
}
}

return c.Holding{}
}

func getLots(lots []c.Lot) map[string]AggregatedLot {
if lots == nil {
return map[string]AggregatedLot{}
}

aggregatedLots := map[string]AggregatedLot{}

for i, lot := range lots {
aggregatedLot, ok := aggregatedLots[lot.Symbol]

if !ok {
aggregatedLots[lot.Symbol] = AggregatedLot{
Symbol: lot.Symbol,
Cost: (lot.UnitCost * lot.Quantity) + lot.FixedCost,
Quantity: lot.Quantity,
OrderIndex: i,
TargetPrice: lot.TargetPrice, // Store the target price from the lot
}
} else {
aggregatedLot.Quantity += lot.Quantity
aggregatedLot.Cost += lot.Quantity * lot.UnitCost

// If the TargetPrice is not set, set it from the lot
if aggregatedLot.TargetPrice == nil && lot.TargetPrice != nil {
aggregatedLot.TargetPrice = lot.TargetPrice
}

aggregatedLots[lot.Symbol] = aggregatedLot
}
}

return aggregatedLots
}

/*
func getLots(lots []c.Lot) map[string]AggregatedLot {

if lots == nil {
Expand Down Expand Up @@ -182,3 +239,4 @@

return aggregatedLots
}
*/
2 changes: 2 additions & 0 deletions internal/common/common.go
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,7 @@ type Lot struct {
Quantity float64 `yaml:"quantity"`
FixedCost float64 `yaml:"fixed_cost"`
// FixedProperties LotFixedProperties `yaml:"fixed_properties"`
TargetPrice *float64 `yaml:"target_price"`
}

// type LotFixedProperties struct {
Expand Down Expand Up @@ -155,6 +156,7 @@ type Holding struct {
DayChange HoldingChange
TotalChange HoldingChange
Weight float64
TargetPrice *float64 // New field for tracking the target price
}

// Currency is the original and converted currency if applicable
Expand Down
Loading