How to add Funds and update online?

Hi ProgFriese, I tried searching but didn’t find anything, but I see that you answer several questions related to the topic and I would appreciate your help. How could I update prices from an Excel or Google Sheet? It would be great, at least for mutual funds, to be able to update NAVs directly from the asset management company’s website. At least here, they usually have historical prices downloadable on their website and are updated daily. I’ve been able to do this with some asset management companies that have published the JSON, but I can’t do it for those that have downloadable Excel or Google Sheets. For example, I can get the prices from this Excel spreadsheet attached to the asset management company’s website. https://cobas-static-content.s3.eu-west-1.amazonaws.com/documentos/cobas/Documentos+web+publica+Yuri+-+ESP/Fondos+de+inversion/Cobas+Internacional/Clase+A/internacional-diario.xlsx

That way, if I could update the prices from there, I wouldn’t be dependent on third-party platforms or websites and they would update more quickly. Thanks!

I have no personal experience with this.

In Kursaktualisierung mit Google Sheets als JSON Endpoint is described how to use a google sheet as json source in PP.

If you want to use an excel sheet as json source, maybe something like xlsx2json-api/README.md at master · tsak/xlsx2json-api · GitHub is useful.

Then you swap the dependency on third-party platforms or websites for the dependency on functioning google sheets or third-party scripts. Is that really better?

This is ISIN ES0119199034?
You can find it
on https://de.investing.com/funds/es0119199034-historical-data as table on a website
or on https://www.morningstar.es/es/funds/snapshot/snapshot.aspx?id=F000016A7T for json

If PP can’t directly obtain the data from those xls files, it’s definitely not a better solution doing it through scripts. I thought there would be a way in PP to directly update prices with the URLs of those xls files, as it does with online boards or JSON. I’ll settle for those third-party platforms obtaining the data from those xls files (all management companies are required to publish it on their websites) and will support delays, errors, or changes to the third-party website. Thanks.

But it is a kind of solution :wink:

package main

import (
	"net/http"
	"fmt"
	"strconv"
	"time"
	"strings"
	"os/exec"
	"log"
)

var isin_map = make(map[string]string)

func cobas_xlsx2json(w http.ResponseWriter, req *http.Request) {
	t := strconv.FormatInt(time.Now().Unix(), 10)
fmt.Println(t, req.URL.Path)
	url_string := strings.TrimPrefix(req.URL.Path, "/")
fmt.Println(url_string)
	urlkey := url_string + "_URL"
	filenamekey := url_string + "_FILENAME"
	sheetnamekey := url_string + "_SHEETNAME"
fmt.Println(t, isin_map[urlkey])
fmt.Println(t, isin_map[filenamekey])
fmt.Println(t, isin_map[sheetnamekey])

// get xlsx file
	getxlsx := "curl --output " + isin_map[filenamekey] + " " + isin_map[urlkey]
fmt.Println(getxlsx)
	curl_out, err := exec.Command("bash", "-c", getxlsx).Output()
	if err != nil {
		log.Fatalln(err)
	}
fmt.Println(curl_out, err)

// convert xlsx to json

	convxlsx := "xlsx2json " + isin_map[filenamekey] + " " + isin_map[sheetnamekey]
fmt.Println(convxlsx)
	conv_out, err := exec.Command("bash", "-c", convxlsx).Output()
	if err != nil {
		log.Fatalln(err)
	}
	str_conv_out := string(conv_out)
fmt.Println(str_conv_out, err)
	jsonstring := strings.Replace(str_conv_out, "[\"Fecha\",\"Liquidativo\"],", "", 1)
fmt.Println(jsonstring)

	fmt.Fprintf(w, jsonstring)
}


func headers(w http.ResponseWriter, req *http.Request) {
	for name, headers := range req.Header {
		for _, h := range headers {
			fmt.Fprintf(w, "%v: %v\n", name, h)
		}
	}
}

func main() {
// ES0119199034
	isin_map["ES0119199034_URL"] = "https://cobas-static-content.s3.eu-west-1.amazonaws.com/documentos/cobas/Documentos+web+publica+Yuri+-+ESP/Fondos+de+inversion/Cobas+Internacional/Clase+A/internacional-diario.xlsx"
	isin_map["ES0119199034_FILENAME"] = "ES0119199034.xlsx"
	isin_map["ES0119199034_SHEETNAME"] = "COBAS_INTERNACIONAL_A"
// ES0119199026
	isin_map["ES0119199026_URL"] = "https://cobas-static-content.s3.eu-west-1.amazonaws.com/documentos/cobas/Documentos+web+publica+Yuri+-+ESP/Fondos+de+inversion/Cobas+Internacional/Clase+B/internacional-diario.xlsx"
	isin_map["ES0119199026_FILENAME"] = "ES0119199026.xlsx"
	isin_map["ES0119199026_SHEETNAME"] = "COBAS_INTERNACIONAL_B"

	http.HandleFunc("/", cobas_xlsx2json)
	http.HandleFunc("/headers", headers)
	http.ListenAndServe(":8083", nil)
}

This is golang, but not completly, it uses curl from my OS and xlsx2json from datatools/xlsx2json.1.md at main · caltechlibrary/datatools · GitHub

It doesn’t look nice, it’s a quick fix, and it’s probably not usable on every OS. But it works as a study.

http://localhost:8083/ES0119199034 or http://localhost:8083/{ISIN}
$[*][0]
yyyy/MM/dd
$[*][1]
1 Like

Thanks, you are so skillful!!. I tried it, I even got as far as using Go and Curl, but then it got complicated because I have Windows, not Linux here… and even trying with Windows, I needed a more recent version, etc., and I’m giving up for today, haha. But thanks, although I insist that what would be great is if they could add it as an add-on to download with XLS in PP as with JSON…

If you are running Windows 10 or 11 use the Powershell command below.

irm https://caltechlibrary.github.io/datatools/installer.ps1 | iex

The IRM command in PowerShell downloads a script from a specified URL, and the IEX command executes it. So you have to trust https://caltechlibrary.github.io/datatools/installer.ps1 on your own responsibility :wink:

1 Like

It was exactly the problem, I still have Windows 7 here hahaha and I used Go 1.17 which was the last compatible one, but then the deepcopy still required Go 1.18 or higher etc. and I gave up… and I’m not keen on running third party scripts, etc… you know… I prefer to run with data from third party websites or platforms :wink:

Well, I’m a bit stubborn, so I finally managed to do it with this script from Windows 7 in case it helps anyone :wink:

package main

import (
	"fmt"
	"log"
	"net/http"
	"os/exec"
	"io/ioutil"
)

// Convertir XLSX a JSON
func convertirXLSXaJSON() error {
	// Ruta de entrada del archivo XLSX
	xlsxFile := "ES0119199034.xlsx"
	// Ruta de salida para el archivo JSON
	jsonFile := "es0119199034-cobas_internacional_a.json"

	// Comando para convertir el XLSX a JSON
	cmd := exec.Command("xlsx2json", xlsxFile, "--sheet", "COBAS_INTERNACIONAL_A", "--output", jsonFile)

	// Ejecutamos el comando
	err := cmd.Run()
	if err != nil {
		return fmt.Errorf("error al ejecutar el comando xlsx2json: %v", err)
	}
	return nil
}

// Handler que maneja la solicitud de /ES0119199034
func handler(w http.ResponseWriter, r *http.Request) {
	// El archivo JSON que queremos servir
	jsonFile := "es0119199034-cobas_internacional_a.json"

	// Leemos el archivo JSON
	jsonData, err := ioutil.ReadFile(jsonFile)
	if err != nil {
		http.Error(w, "No se pudo leer el archivo JSON", http.StatusInternalServerError)
		return
	}

	// Establecer la cabecera de respuesta para indicar que es un JSON
	w.Header().Set("Content-Type", "application/json")
	// Escribir el contenido del JSON en la respuesta
	w.WriteHeader(http.StatusOK)
	w.Write(jsonData)
}

func main() {
	// Convertimos el archivo XLSX a JSON antes de iniciar el servidor
	err := convertirXLSXaJSON()
	if err != nil {
		log.Fatal("Error al convertir el archivo XLSX a JSON:", err)
	}

	// Ruta para manejar la solicitud de /ES0119199034
	http.HandleFunc("/ES0119199034", handler)

	// Iniciar el servidor en http://localhost:8083
	fmt.Println("Servidor iniciado en http://localhost:8083")
	log.Fatal(http.ListenAndServe(":8083", nil))
}

1 Like