From 9fb57845edaa4f8b68f1aceb2a94c888300fd32e Mon Sep 17 00:00:00 2001 From: Antoine Meillet Date: Sat, 27 Mar 2021 21:42:28 +0100 Subject: [PATCH] Add Yahoo Finance module (#1066) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Move finnhub to a stocks folder As I am preparing an other stocks data provider, let's move `finnhub` to a stocks folder that will host the others providers. * Use go-pretty v6 Will be used by the new stock provider module, so let's just upgrade this one to reduce the number of dependencies. * Add Yahoo Finance module Yahoo Finance provides an API for which `piquette/finance-go` is a powerful client. This new module leverages this module to integrate all indices provided by Yahoo Finance (international stocks, crypto, options, currencies...) Sample config: ```yaml yfinance: title: "Stocks 🚀" symbols: - "MSFT" - "GC=F" - "ORA.PA" sort: true enabled: true refreshInterval: 60 position: top: 1 left: 0 height: 1 width: 1 ``` --- app/widget_maker.go | 6 +- go.mod | 5 +- go.sum | 26 ++-- modules/{ => stocks}/finnhub/client.go | 0 modules/{ => stocks}/finnhub/quote.go | 0 modules/{ => stocks}/finnhub/settings.go | 0 modules/{ => stocks}/finnhub/widget.go | 2 +- modules/stocks/yfinance/settings.go | 45 +++++++ modules/stocks/yfinance/widget.go | 74 ++++++++++++ modules/stocks/yfinance/yquote.go | 145 +++++++++++++++++++++++ 10 files changed, 284 insertions(+), 19 deletions(-) rename modules/{ => stocks}/finnhub/client.go (100%) rename modules/{ => stocks}/finnhub/quote.go (100%) rename modules/{ => stocks}/finnhub/settings.go (100%) rename modules/{ => stocks}/finnhub/widget.go (96%) create mode 100644 modules/stocks/yfinance/settings.go create mode 100644 modules/stocks/yfinance/widget.go create mode 100644 modules/stocks/yfinance/yquote.go diff --git a/app/widget_maker.go b/app/widget_maker.go index 30dbbd59..08c78647 100644 --- a/app/widget_maker.go +++ b/app/widget_maker.go @@ -25,7 +25,6 @@ import ( "github.com/wtfutil/wtf/modules/docker" "github.com/wtfutil/wtf/modules/exchangerates" "github.com/wtfutil/wtf/modules/feedreader" - "github.com/wtfutil/wtf/modules/finnhub" "github.com/wtfutil/wtf/modules/football" "github.com/wtfutil/wtf/modules/gcal" "github.com/wtfutil/wtf/modules/gerrit" @@ -62,6 +61,8 @@ import ( "github.com/wtfutil/wtf/modules/spotify" "github.com/wtfutil/wtf/modules/spotifyweb" "github.com/wtfutil/wtf/modules/status" + "github.com/wtfutil/wtf/modules/stocks/finnhub" + "github.com/wtfutil/wtf/modules/stocks/yfinance" "github.com/wtfutil/wtf/modules/subreddit" "github.com/wtfutil/wtf/modules/textfile" "github.com/wtfutil/wtf/modules/todo" @@ -332,6 +333,9 @@ func MakeWidget( case "finnhub": settings := finnhub.NewSettingsFromYAML(moduleName, moduleConfig, config) widget = finnhub.NewWidget(tviewApp, settings) + case "yfinance": + settings := yfinance.NewSettingsFromYAML(moduleName, moduleConfig, config) + widget = yfinance.NewWidget(tviewApp, settings) default: settings := unknown.NewSettingsFromYAML(moduleName, moduleConfig, config) widget = unknown.NewWidget(tviewApp, settings) diff --git a/go.mod b/go.mod index f50f09af..2c6bc24d 100644 --- a/go.mod +++ b/go.mod @@ -26,13 +26,12 @@ require ( github.com/dustin/go-humanize v1.0.0 github.com/gdamore/tcell v1.4.0 github.com/go-ole/go-ole v1.2.4 // indirect - github.com/go-openapi/strfmt v0.19.6 // indirect github.com/godbus/dbus v4.1.0+incompatible // indirect github.com/google/go-github/v32 v32.1.0 github.com/gophercloud/gophercloud v0.5.0 // indirect github.com/hekmon/cunits v2.0.1+incompatible // indirect github.com/hekmon/transmissionrpc v0.0.0-20190525133028-1d589625bacd - github.com/jedib0t/go-pretty v4.3.0+incompatible + github.com/jedib0t/go-pretty/v6 v6.1.0 github.com/jessevdk/go-flags v1.4.0 github.com/lib/pq v1.2.0 // indirect github.com/logrusorgru/aurora v0.0.0-20190803045625-94edacc10f9b @@ -45,11 +44,13 @@ require ( github.com/onsi/gomega v1.9.0 // indirect github.com/ovh/cds v0.0.0-20201014170613-39429542624d github.com/pborman/uuid v1.2.0 // indirect + github.com/piquette/finance-go v1.0.0 github.com/pkg/errors v0.9.1 github.com/pkg/profile v1.5.0 github.com/radovskyb/watcher v1.0.7 github.com/rivo/tview v0.0.0-20200108161608-1316ea7a4b35 github.com/shirou/gopsutil v2.20.9+incompatible + github.com/shopspring/decimal v1.2.0 // indirect github.com/shurcooL/githubv4 v0.0.0-20200802174311-f27d2ca7f6d5 github.com/shurcooL/graphql v0.0.0-20181231061246-d48a9a75455f // indirect github.com/spf13/cobra v0.0.5 // indirect diff --git a/go.sum b/go.sum index 8a143ed5..7ad50e4b 100644 --- a/go.sum +++ b/go.sum @@ -95,8 +95,6 @@ github.com/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY= github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= -github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a h1:idn718Q4B6AGu/h5Sxe66HYVdqdGu2l9Iebqhi/AEoA= -github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY= github.com/aws/aws-sdk-go v1.19.11/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= @@ -185,6 +183,7 @@ github.com/fsamin/go-shredder v0.0.0-20180118184739-b2488aedb5be/go.mod h1:kuiNc github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/fujiwara/shapeio v0.0.0-20170602072123-c073257dd745/go.mod h1:/WpqsrSkjgwEG2Es2qnZXbXwHDVbawpdlXJIjJMmnZs= +github.com/fzipp/gocyclo v0.3.1/go.mod h1:DJHO6AUmbdqj2ET4Z9iArSuwWgYDRryYt2wASxc7x3E= github.com/gambol99/go-marathon v0.0.0-20170922093320-ec4a50170df7/go.mod h1:GLyXJD41gBO/NPKVPGQbhyyC06eugGy15QEZyUkE2/s= github.com/gdamore/encoding v1.0.0 h1:+7OoQ1Bc6eTm5niUzBa0Ctsh6JbMW6Ra+YNuAtDBdko= github.com/gdamore/encoding v1.0.0/go.mod h1:alR0ol34c49FCSBLjhosxzcPHQbf2trDkoo5dl+VrEg= @@ -205,14 +204,9 @@ github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9 github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= github.com/go-ole/go-ole v1.2.4 h1:nNBDSCOigTSiarFpYE9J/KtEA1IOW4CNeqT9TQDqCxI= github.com/go-ole/go-ole v1.2.4/go.mod h1:XCwSNxSkXRo4vlyPy93sltvi/qJq0jqQhjqQNIwKuxM= -github.com/go-openapi/errors v0.19.2 h1:a2kIyV3w+OS3S97zxUndRVD46+FhGOUBDFY7nmu4CsY= -github.com/go-openapi/errors v0.19.2/go.mod h1:qX0BLWsyaKfvhluLejVpVNwNRdXZhEbTA4kxxpKBC94= -github.com/go-openapi/strfmt v0.19.6 h1:epWc+q5qSgsy7A7+/HYyxLF37vLEYdPSkNB9G8mRqjw= -github.com/go-openapi/strfmt v0.19.6/go.mod h1:eftuHTlB/dI8Uq8JJOyRlieZf+WkkxUuk0dgdHXr2Qk= github.com/go-redis/redis v6.15.2+incompatible/go.mod h1:NAIEuMOZ/fxfXJIrKDQDz8wamY7mA7PouImQ2Jvg6kA= github.com/go-sql-driver/mysql v1.4.1 h1:g24URVg0OFbNUTx9qqY1IRZ9D9z3iPyi5zKhQZpNwpA= github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= -github.com/go-stack/stack v1.8.0 h1:5SgMzNM5HxrEjV0ww2lTmX6E2Izsfxas4+YHWRs3Lsk= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/go-test/deep v1.0.2-0.20181118220953-042da051cf31/go.mod h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3aSFNA= github.com/godbus/dbus v4.1.0+incompatible h1:WqqLRTsQic3apZUK9qC5sGNfXthmPXzUZ7nQPrNITa4= @@ -352,8 +346,8 @@ github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NH github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= github.com/itsjamie/gin-cors v0.0.0-20160420130702-97b4a9da7933/go.mod h1:AYdLvrSBFloDBNt7Y8xkQ6gmhCODGl8CPikjyIOnNzA= github.com/jcmturner/gofork v1.0.0/go.mod h1:MK8+TM0La+2rjBD4jE12Kj1pCCxK7d2LK/UM3ncEo0o= -github.com/jedib0t/go-pretty v4.3.0+incompatible h1:CGs8AVhEKg/n9YbUenWmNStRW2PHJzaeDodcfvRAbIo= -github.com/jedib0t/go-pretty v4.3.0+incompatible/go.mod h1:XemHduiw8R651AF9Pt4FwCTKeG3oo7hrHJAoznj9nag= +github.com/jedib0t/go-pretty/v6 v6.1.0 h1:NVS2PT3ZvzMb47DzS50cmsK6xkf8SSyLfroSSIG20JI= +github.com/jedib0t/go-pretty/v6 v6.1.0/go.mod h1:+nE9fyyHGil+PuISTCrp7avEdo6bqoMwqZnuiK2r2a0= github.com/jessevdk/go-flags v1.4.0 h1:4IU2WS7AumrZ/40jfhf4QVDMsQwqA7VEHozFRrGARJA= github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= @@ -414,8 +408,9 @@ github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHX github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= github.com/mattn/go-runewidth v0.0.1/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= github.com/mattn/go-runewidth v0.0.4/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= -github.com/mattn/go-runewidth v0.0.7 h1:Ei8KR0497xHyKJPAv59M1dkC+rOZCMBJ+t3fZ+twI54= github.com/mattn/go-runewidth v0.0.7/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= +github.com/mattn/go-runewidth v0.0.9 h1:Lm995f3rfxdpd6TSmuVCHVb/QhupuXlYr8sCI/QdE+0= +github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= github.com/mattn/go-sqlite3 v1.9.0 h1:pDRiWfl+++eC2FEFRy6jXmQlvp4Yh3z1MJKg4UeYM/4= github.com/mattn/go-sqlite3 v1.9.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= github.com/mattn/go-zglob v0.0.1/go.mod h1:9fxibJccNxU2cnpIKLRRFA7zX7qhkJIQWBb449FYHOo= @@ -502,11 +497,14 @@ github.com/peterbourgon/diskv v2.0.1+incompatible h1:UBdAOUP5p4RWqPBg048CAvpKN+v github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU= github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= github.com/pierrec/lz4 v2.5.2+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= +github.com/piquette/finance-go v1.0.0 h1:0nHbZCbhAsUMUt18oTgy5bHQfPRGhcNA0EbpxNRsZAA= +github.com/piquette/finance-go v1.0.0/go.mod h1:H51NoGFnfu41Un/Fp0aAhS2lLRFBiiwHhMsV59bXAI0= github.com/pkg/browser v0.0.0-20170505125900-c90ca0c84f15/go.mod h1:4OwLy04Bl9Ef3GJJCoec+30X3LQs/0/m4HFRt/2LUSA= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/profile v1.2.1/go.mod h1:hJw3o1OdXxsrSjjVksARp5W95eeEaEfptyVZyv6JUPA= github.com/pkg/profile v1.5.0 h1:042Buzk+NhDI+DeSAA62RwJL8VAuZUMQZUjCsRz1Mug= github.com/pkg/profile v1.5.0/go.mod h1:qBsxPvzyUincmltOk6iyRVxHYg4adc0OFOv72ZdLa18= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= @@ -566,6 +564,8 @@ github.com/sguiheux/go-coverage v0.0.0-20190710153556-287b082a7197/go.mod h1:0hh github.com/shirou/gopsutil v0.0.0-20170406131756-e49a95f3d5f8/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA= github.com/shirou/gopsutil v2.20.9+incompatible h1:msXs2frUV+O/JLva9EDLpuJ84PrFsdCTCQex8PUdtkQ= github.com/shirou/gopsutil v2.20.9+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA= +github.com/shopspring/decimal v1.2.0 h1:abSATXmQEYyShuxI4/vyW3tV1MrKAJzCZ/0zLUXYbsQ= +github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o= github.com/shurcooL/githubv4 v0.0.0-20200802174311-f27d2ca7f6d5 h1:CA6Mjshr+g5YHENwllpQNR0UaYO7VGKo6TzJLM64WJQ= github.com/shurcooL/githubv4 v0.0.0-20200802174311-f27d2ca7f6d5/go.mod h1:hAF0iLZy4td2EX+/8Tw+4nodhlMrwN3HupfaXj3zkGo= github.com/shurcooL/graphql v0.0.0-20181231061246-d48a9a75455f h1:tygelZueB1EtXkPI6mQ4o9DQ0+FKW41hTbunoXZCTqk= @@ -604,7 +604,6 @@ github.com/ssor/bom v0.0.0-20170718123548-6386211fdfcf/go.mod h1:RJID2RhlZKId02n github.com/streadway/amqp v0.0.0-20180528204448-e5adc2ada8b8/go.mod h1:1WNBiOZtZQLpVAyu0iTduoJL9hEsMloAK5XWrtW0xdY= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.3.1-0.20190311161405-34c6fa2dc709/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= @@ -617,8 +616,6 @@ github.com/studio-b12/gowebdav v0.0.0-20200303150724-9380631c29a1/go.mod h1:gCcf github.com/subosito/gotenv v1.2.0 h1:Slr1R9HxAlEKefgq5jn9U+DnETlIUa6HfgEzj0g5d7s= github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= github.com/tevino/abool v0.0.0-20170917061928-9b9efcf221b5/go.mod h1:f1SCnEOt6sc3fOJfPQDRDzHOtSXuTtnz0ImG9kPRDV0= -github.com/tidwall/pretty v1.0.0 h1:HsD+QiTn7sK6flMKIvNmpqz1qrpP3Ps6jOKIKMooyg4= -github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk= github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc= github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw= @@ -656,8 +653,6 @@ github.com/zorkian/go-datadog-api v2.30.0+incompatible h1:R4ryGocppDqZZbnNc5EDR8 github.com/zorkian/go-datadog-api v2.30.0+incompatible/go.mod h1:PkXwHX9CUQa/FpB9ZwAD45N1uhCW4MT/Wj7m36PbKss= go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= -go.mongodb.org/mongo-driver v1.0.3 h1:GKoji1ld3tw2aC+GX1wbr/J2fX13yNacEYoJ8Nhr0yU= -go.mongodb.org/mongo-driver v1.0.3/go.mod h1:u7ryQJ+DOzQmeO7zB6MHyr8jkEQvC8vH7qLUO4lqsUM= go.opencensus.io v0.20.1/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk= go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= @@ -763,6 +758,7 @@ golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208 h1:qwRHBd0NqMbJxfbotnDhm2ByMI1Shq4Y6oRJo21SGJA= golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20180816055513-1c9583448a9c/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= diff --git a/modules/finnhub/client.go b/modules/stocks/finnhub/client.go similarity index 100% rename from modules/finnhub/client.go rename to modules/stocks/finnhub/client.go diff --git a/modules/finnhub/quote.go b/modules/stocks/finnhub/quote.go similarity index 100% rename from modules/finnhub/quote.go rename to modules/stocks/finnhub/quote.go diff --git a/modules/finnhub/settings.go b/modules/stocks/finnhub/settings.go similarity index 100% rename from modules/finnhub/settings.go rename to modules/stocks/finnhub/settings.go diff --git a/modules/finnhub/widget.go b/modules/stocks/finnhub/widget.go similarity index 96% rename from modules/finnhub/widget.go rename to modules/stocks/finnhub/widget.go index 27279ba5..694128c8 100644 --- a/modules/finnhub/widget.go +++ b/modules/stocks/finnhub/widget.go @@ -3,7 +3,7 @@ package finnhub import ( "fmt" - "github.com/jedib0t/go-pretty/table" + "github.com/jedib0t/go-pretty/v6/table" "github.com/rivo/tview" "github.com/wtfutil/wtf/view" ) diff --git a/modules/stocks/yfinance/settings.go b/modules/stocks/yfinance/settings.go new file mode 100644 index 00000000..9e06c1e4 --- /dev/null +++ b/modules/stocks/yfinance/settings.go @@ -0,0 +1,45 @@ +package yfinance + +import ( + "github.com/olebedev/config" + "github.com/wtfutil/wtf/cfg" + "github.com/wtfutil/wtf/utils" +) + +const ( + defaultFocusable = false + defaultTitle = "Yahoo Finance" +) + +type colors struct { + bigup string + up string + drop string + bigdrop string +} + +// Settings defines the configuration properties for this module +type Settings struct { + common *cfg.Common + + colors colors + sort bool + symbols []string `help:"An array of Yahoo Finance symbols (for example: DOCN, GME, GC=F)"` +} + +// NewSettingsFromYAML creates a new settings instance from a YAML config block +func NewSettingsFromYAML(name string, ymlConfig *config.Config, globalConfig *config.Config) *Settings { + settings := Settings{ + common: cfg.NewCommonSettingsFromModule(name, defaultTitle, defaultFocusable, ymlConfig, globalConfig), + // RefreshInterval: , + } + + settings.common.RefreshInterval = ymlConfig.UInt("refreshInterval", 60) + settings.colors.bigup = ymlConfig.UString("colors.bigup", "greenyellow") + settings.colors.up = ymlConfig.UString("colors.up", "green") + settings.colors.drop = ymlConfig.UString("colors.drop", "firebrick") + settings.colors.bigdrop = ymlConfig.UString("colors.bigdrop", "red") + settings.sort = ymlConfig.UBool("sort", false) + settings.symbols = utils.ToStrs(ymlConfig.UList("symbols")) + return &settings +} diff --git a/modules/stocks/yfinance/widget.go b/modules/stocks/yfinance/widget.go new file mode 100644 index 00000000..f5303f31 --- /dev/null +++ b/modules/stocks/yfinance/widget.go @@ -0,0 +1,74 @@ +package yfinance + +import ( + "fmt" + "sort" + + "github.com/jedib0t/go-pretty/v6/table" + "github.com/rivo/tview" + "github.com/wtfutil/wtf/view" +) + +// Widget is the container for your module's data +type Widget struct { + view.TextWidget + + settings *Settings +} + +// NewWidget creates and returns an instance of Widget +func NewWidget(tviewApp *tview.Application, settings *Settings) *Widget { + widget := Widget{ + TextWidget: view.NewTextWidget(tviewApp, nil, settings.common), + + settings: settings, + } + + return &widget +} + +/* -------------------- Exported Functions -------------------- */ + +// Refresh updates the onscreen contents of the widget +func (widget *Widget) Refresh() { + + // The last call should always be to the display function + widget.display() +} + +/* -------------------- Unexported Functions -------------------- */ + +func (widget *Widget) content() string { + yquotes := quotes(widget.settings.symbols) + + colors := map[string]string{ + "bigup": widget.settings.colors.bigup, + "up": widget.settings.colors.up, + "drop": widget.settings.colors.drop, + "bigdrop": widget.settings.colors.bigdrop, + } + + if widget.settings.sort { + sort.SliceStable(yquotes, func(i, j int) bool { return yquotes[i].MarketChangePct > yquotes[j].MarketChangePct }) + } + + t := table.NewWriter() + t.SetStyle(tableStyle()) + for _, yq := range yquotes { + t.AppendRow([]interface{}{ + GetMarketIcon(yq.MarketState), + yq.Symbol, + fmt.Sprintf("%8.2f %s", yq.MarketPrice, yq.Currency), + GetTrendIcon(yq.Trend), + fmt.Sprintf("[%s]%+6.2f (%+5.2f%%)", colors[yq.Trend], yq.MarketChange, yq.MarketChangePct), + }) + } + + return t.Render() +} + +func (widget *Widget) display() { + widget.Redraw(func() (string, string, bool) { + return widget.CommonSettings().Title, widget.content(), false + }) +} diff --git a/modules/stocks/yfinance/yquote.go b/modules/stocks/yfinance/yquote.go new file mode 100644 index 00000000..1dc256bf --- /dev/null +++ b/modules/stocks/yfinance/yquote.go @@ -0,0 +1,145 @@ +package yfinance + +import ( + "github.com/jedib0t/go-pretty/v6/table" + "github.com/jedib0t/go-pretty/v6/text" + "github.com/piquette/finance-go/quote" +) + +type MarketState string + +type yquote struct { + Trend string // can be bigup (>3%), up, drop or bigdrop (<3%) + Symbol string + Currency string + MarketState string + MarketPrice float64 + MarketChange float64 + MarketChangePct float64 +} + +func tableStyle() table.Style { + return table.Style{ + Name: "yfinance", + Box: table.BoxStyle{ + BottomLeft: "", + BottomRight: "", + BottomSeparator: "", + Left: "", + LeftSeparator: "", + MiddleHorizontal: " ", + MiddleSeparator: "", + MiddleVertical: "", + PaddingLeft: " ", + PaddingRight: "", + Right: "", + RightSeparator: "", + TopLeft: "", + TopRight: "", + TopSeparator: "", + UnfinishedRow: "", + }, + Color: table.ColorOptions{ + Footer: text.Colors{}, + Header: text.Colors{}, + Row: text.Colors{}, + RowAlternate: text.Colors{}, + }, + Format: table.FormatOptions{ + Footer: text.FormatUpper, + Header: text.FormatUpper, + Row: text.FormatDefault, + }, + Options: table.Options{ + DrawBorder: false, + SeparateColumns: false, + SeparateFooter: false, + SeparateHeader: false, + SeparateRows: false, + }, + } +} + +func quotes(symbols []string) []yquote { + var yquotes []yquote + for _, symbol := range symbols { + var yq yquote + + var MarketPrice float64 + var MarketChange float64 + var MarketChangePct float64 + + q, err := quote.Get(symbol) + if q == nil || err != nil { + yq = yquote{ + Symbol: symbol, + Trend: "?", + MarketState: "?", + } + } else { + if q.MarketState == "PRE" { + MarketPrice = q.PreMarketPrice + MarketChange = q.PreMarketChange + MarketChangePct = q.PreMarketChangePercent + + } else if q.MarketState == "POST" { + MarketPrice = q.PostMarketPrice + MarketChange = q.PostMarketChange + MarketChangePct = q.PostMarketChangePercent + } else { + MarketPrice = q.RegularMarketPrice + MarketChange = q.RegularMarketChange + MarketChangePct = q.RegularMarketChangePercent + } + yq = yquote{ + Symbol: q.Symbol, + Currency: q.CurrencyID, + Trend: GetTrend(MarketChangePct), + MarketState: string(q.MarketState), + MarketPrice: MarketPrice, + MarketChange: MarketChange, + MarketChangePct: MarketChangePct, + } + } + yquotes = append(yquotes, yq) + } + return yquotes +} + +func GetMarketIcon(state string) string { + states := map[string]string{ + "PRE": "⏭", + "REGULAR": "▶", + "POST": "⏮", + "?": "?", + } + if icon, ok := states[state]; ok { + return icon + } else { + return "⏹" + } +} + +func GetTrendIcon(trend string) string { + icons := map[string]string{ + "bigup": "⬆️ ", + "up": "↗️ ", + "drop": "↘️ ", + "bigdrop": "⬇️ ", + } + return icons[trend] +} + +func GetTrend(pct float64) string { + var trend string + if pct > 3 { + trend = "bigup" + } else if pct > 0 { + trend = "up" + } else if pct > -3 { + trend = "drop" + } else { + trend = "bigdrop" + } + return trend +}