Skip to content
Closed
Show file tree
Hide file tree
Changes from 1 commit
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"]
6 changes: 6 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
module github.com/achannarasappa/ticker/v5

<<<<<<< HEAD
Comment thread
YangChaoChung marked this conversation as resolved.
Outdated
go 1.24.3
=======
go 1.19
>>>>>>> fcb122a (Tracking the target price)

require (
github.com/acarl005/stripansi v0.0.0-20180116102854-5a71ef0e047d
Expand Down Expand Up @@ -60,3 +64,5 @@ require (
google.golang.org/protobuf v1.36.6 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)

// replace github.com/achannarasappa/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 @@ import (
"strings"

c "github.com/achannarasappa/ticker/v5/internal/common"
"fmt"
"github.com/achannarasappa/ticker/v4/internal/currency"
// "github.com/achannarasappa/ticker/internal/alert"
)

// AggregatedLot represents a cost basis lot of an asset grouped by symbol
Expand All @@ -12,6 +15,7 @@ type AggregatedLot struct {
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 @@ func GetAssets(ctx c.Context, assetGroupQuote c.AssetGroupQuote) ([]c.Asset, Hol

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 updateHoldingWeights(assets []c.Asset, holdingSummary HoldingSummary) []c.A

}

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 @@ func getHoldingFromAssetQuote(assetQuote c.AssetQuote, lotsBySymbol map[string]A
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 @@ func getLots(lots []c.Lot) map[string]AggregatedLot {

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