Ga naar hoofdinhoud

Algorithmisch traden in R: tutorial

In deze R-tutorial doe je webscraping, gebruik je een finance-API en een htmlwidget om een interactieve tijdreeksdiagram te maken voor een eenvoudige algorithmische tradingstrategie
Bijgewerkt 2 okt 2026  · 15 min lezen

Verken met AI

ChatGPTClaudePerplexity

In deze post laat ik zien hoe je met R de aandelen op loyal3 verzamelt, historische data van Yahoo ophaalt en vervolgens een simpele algorithmische tradingstrategie uitvoert. Onderweg leer je webscraping, een functie die een finance-API aanroept en een htmlwidget om een interactieve tijdreeksdiagram te maken.

Voor deze post definiëren we een tradingalgo als een set regels die een koop- of verkoopsignaal geven, in plaats van een voorspellend model of een tijdreeksforecast. Dit is het simpelste type tradingalgo, maar als je dieper wilt duiken in finance met R, raad ik je aan DataCamp’s cursus over het modelleren van een kwantitatieve tradingstrategie in R te volgen.

Achtergrond

In 2015 begon ik met een klein bedrag te beleggen bij loyal3. Hun service is ongebruikelijk en een prima plek om je beleggingsreis te starten. In plaats van de belegger transactiekosten te rekenen, rekent loyal3 de bedrijven om op hun platform te staan. Het idee is dat mensen die de service van een bedrijf waarderen, ook het aandeel kopen en zo sterke merkambassadeurs worden. Extra aantrekkelijk is dat je fracties van aandelen kunt kopen. Je kunt dus instappen in dat $800 Amazon-aandeel voor slechts $10 en elke keer dat je aan het eind van de maand wat extra geld overhoudt nog eens $10 bijleggen. Natuurlijk zijn er frictiekosten, omdat je in vensters moet handelen en je hele portfolio beperkt is tot ~70 aandelen, maar loyal3 is een leuke en goedkope manier om aandelenhandel te verkennen. Je kunt al meedoen met echt geld vanaf $10!

Voor de duidelijkheid: ik heb de gebruikelijke pensioen- en beleggingsrekeningen, maar ik vind de strakke interface van loyal3’s app en het ontbreken van kosten prettig. Ik check mijn leuke loyal3-portfolio vaker dan mijn beleggingsfondsen, simpelweg omdat het makkelijk en leuk is om de prestaties te zien van de aandelen die ik zelf heb uitgekozen.

algorithmic trading R
De aandelen die beschikbaar zijn op www.loyal3.com

Je werkruimte instellen

Begin met het laden van de libraries in je omgeving. Ik gebruik tegenwoordig bijna altijd rvest voor webscraping. Er zijn andere pakketten die ook werken, zoals RSelenium, maar ik vind hoe eenvoudig rvest uit te voeren is prettig.

Het tweede pakket, pbapply, is optioneel, omdat het simpelweg een voortgangsbalk toevoegt aan de apply-functies. Omdat je honderden webpagina’s kunt scrapen, is een voortgangsbalk handig om de tijd in te schatten.

Vervolgens is TTR een pakket dat ik net ben gaan verkennen. De library wordt gebruikt om “Technical Trading Rules” te bouwen. Hoewel je in deze post een eenvoudige tradingalgo leert, kan het TTR-pakket meer geavanceerde berekeningen uitvoeren en is het de moeite waard om te leren.

De dygraphs-library is een wrapper rond een snelle, open-source JavaScript-chartinglibrary. Het is een van de htmlwidgets die R-grafieken dynamischer maakt en onderdeel van een html-bestand in plaats van een statische afbeelding. Tot slot gebruik je het lubridate-pakket voor eenvoudige datum­manipulatie.

library(rvest)
library(pbapply)
library(TTR)
library(dygraphs)
library(lubridate)

Dataverzameling

Alle loyal3-aandelen staan op één pagina. Voordat je individuele dagelijkse koersdata kunt opzoeken om je tradingalgoritme te bouwen, moet je alle beschikbare tickers verzamelen. Het eerste wat je doet is stock.list als URL-string declareren. Gebruik daarna read_html() zodat je R-sessie een internetsessie opent en alle html-informatie op de pagina verzamelt als een XML-nodeset. De CSS op de pagina heeft een ID genaamd “.company-name”. Gebruik dit als parameter bij het aanroepen van html_nodes() om alleen de XML-data te selecteren die bij deze node hoort. Gebruik tot slot html_text() om de daadwerkelijke tekstwaarden voor de bedrijfsnamen te verzamelen.

stock.list<-'https://www.loyal3.com/stocks'
stocks<-read_html(stock.list)
stocks.names<-html_nodes(stocks,'.company-name')
stocks.names<-html_text(stocks.names)

Om de aandelen die beschikbaar zijn op loyal3 te bekijken, kun je het object stocks.names naar je console printen. Dit geeft de bedrijfsnaam terug als tekstvector.

stocks.names 

Om de koersen te onderzoeken, heb je eerst de tickersymbolen nodig. Op de loyal3-site kun je op de tegel van een bedrijf klikken om een pagina te laden met het tickersymbool en andere bedrijfsinformatie.

Met html_nodes() op stocks haal je alle nodes op die gemarkeerd zijn met een “a”. In HTML definieert de tag <a> een hyperlink die wordt gebruikt om van de ene naar de andere pagina te linken. Binnen de hyperlinktag verwijst “href” naar het exacte URL-adres. html_attr() zal dus de URL voor ALLE links op de pagina extraheren als je “href” meegeeft.

Na wat handmatige inspectie zag ik dat de 54e tot en met de 123e link op de pagina de bedrijfspagina’s zijn die ik nodig heb om de tickerinformatie te scrapen. De laatste regel gebruikt paste0() om de basis-URL-string ’http://www.loyal3.com` te concateneren met de specifieke bedrijfspagina’s, zoals “/WALMART”. Bijvoorbeeld, http://www.loyal3.com/WALMART:

loyal.links<-html_nodes(stocks, "a")
loyal.links<-html_attr(loyal.links, "href")
stock.links<-paste0('http://www.loyal3.com',loyal.links[54:123])

Op elke bedrijfspagina staat een beschrijving, een recente slotkoers en de ticker. Alle bedrijfspagina’s zijn hetzelfde opgebouwd, dus de customfunctie get.ticker() kan worden gebruikt om het tickersymbool te extraheren.

Op de webpagina van een bedrijf staat een tabel genaamd “ticker-price”. De functie navigeert naar een bedrijfspagina, identificeert de juiste tabel en extraheert de tekst met html_text(). Tot slot, met sub() samen met de reguliere expressie ^([[:alpha:]]*).* en \\1 worden alle alfabetische karakters behouden. Het resultaat is dat speciale tekens, zoals $, en numerieke karakters, zoals de slotkoers, worden verwijderd. Terwijl de functie elk van de 70 pagina’s leest, verzamelt hij alleen de ticker.

 get.ticker<-function(url){
  x<-read_html(url)
  x<-html_node(x,'.ticker-price')
  x<-html_text(x)
  x<-sub("^([[:alpha:]]*).*", "\\1", x)
  return(x)
  } 
loyal3-aandelenpagina voor Alibaba
de loyal3-aandelenpagina voor Alibaba, waar je de tabel met de ticker van het aandeel, BABA, onder de vetgedrukte tekst ziet

Gewapend met je customfunctie gebruik je pblapply() om deze toe te passen op elk van de stock.links die de pagina’s van de individuele bedrijven bevatten. Het resulterende object, stock.tickers, is een lijst met individuele tickers waarbij elk element overeenkomt met één bedrijf.

stock.tickers<-pblapply(stock.links,get.ticker)

Een manier om een lijst met elementen om te zetten in een vlak object is met do.call(). Hier pas je rbind toe om elk listelement rij-voor-rij te binden tot één vector. Tot slot maak je een data frame met de symbolen en bedrijfsnamen.

stock.ticks<-do.call(rbind,stock.tickers)
stock.ticks<-data.frame(symbol=stock.ticks,name=stocks.names)

Om consistent te blijven in je analyse, wil je misschien de hoeveelheid historische informatie per aandeel beperken. De functie Sys.Data() slaat een datumobject op als jaar, maand en dag. Jaren met een integer gebruiken is één manier om een specifieke hoeveelheid tijd van het object start.date af te trekken.

start.date<-Sys.Date()
end.date<-Sys.Date()-years(3)

Om de Yahoo Finance-data op te halen, moet het datumobject worden omgezet in eenvoudige tekst zonder streepjes. Met de globale vervangingsfunctie gsub() op zowel start.date als end.date verander je de klasse en verwijder je tegelijk de streepjes. In gsub() geef je het patroon door waarnaar gezocht moet worden en vervolgens de vervangende tekens. In dit geval is het vervangingspatroon een lege string tussen aanhalingstekens. De laatste parameter is het object waarop gsub() wordt toegepast.

start.date<-gsub('-','', start.date)
end.date<-gsub('-','', end.date)

De TTR()-functie getYahooData() accepteert een aandelensymbool en een begin- en einddatum. De functie retourneert een data frame met tijdreeksinformatie. Elke rij is een datum en de kolommen bevatten informatie zoals de “Open”, “High”, “Low” en “Closing”-koers van een aandeel. Omdat je meerdere bedrijven opzoekt, kun je lapply() of pblapply() gebruiken. Geef de vector met aandelensymbolen door, vervolgens de functie getYahooData(), en dan de datuminformatie. De date-objecten worden hergebruikt elke keer dat getYahooData() wordt toegepast op een symbool.

 stocks.ts<-pblapply(stock.ticks$symbol,getYahooData,end.date, start.date)

Om de geretourneerde lijst, stocks.ts, makkelijker te doorzoeken, kun je namen aan de listelementen toevoegen. Gebruik names met het object stocks.ts en stel de namen in op de oorspronkelijke $symbol-vector.

names(stocks.ts)<-stock.ticks$symbol

Als ik met grote lijsten werk, bekijk ik graag het resulterende object om te controleren of de uitkomst is wat ik verwachtte. Nu de elementen namen hebben, kun je ze direct benaderen. In dit voorbeeld bekijk je de eerste 6 rijen voor AMC Entertainment Holdings (AMC). Met head() op de lijst terwijl je $AMC aanroept, krijg je een deel van de tijdreeks voor dit aandeel terug:

head(stocks.ts$AMC)

De koersdata onderzoeken

Als ik naar financieel nieuws luister, verwijzen commentatoren vaak naar grafieken. Ondanks high-frequency trading en actief beheer door anderen, kijken veel particuliere beleggers nog steeds naar grafieken voor inzicht. Het tijdreeksobject kun je snel weergeven met plot. Geef de lijst door met verwijzing naar het benoemde element, zoals $AMC, en dan de kolom die je wilt tonen, hier $Close.

plot(stocks.ts$AMZN$Close)
stocks-plot

De bovenstaande plot is statisch en niet erg spannend.

Laten we een JavaScript-library gebruiken om een grafiek te maken die je kunt verkennen. In deze codefragmenten zie je mogelijk de “%>%” of pipe-operator. De pipe-operator is een goede manier om beknopte code te schrijven. Hij stuurt een object door naar de volgende functie zonder dat je de objectnaam opnieuw hoeft te schrijven, zoals je eerder in deze post deed.

In dit voorbeeld maak je een dygraph met verwijzing naar het Twitter-aandeel, $TWTR, en vervolgens de kolom die je wilt plotten, $Close. Binnen dygraph voegt main een titel toe die je tussen aanhalingstekens opgeeft. Met de “%>%” wordt dit volledige object doorgestuurd naar de volgende functie dyRangeSelector(). Je kunt een standaarddaterange opgeven met c() met een start- en einddatumstring. Het resulterende HTML-object is een dynamische tijdreeks voor het Twitter-aandeel met een datumschuif onderaan.

Onthoud: om het weergegeven aandeel te wijzigen, verander je het tickersymbool in de stocks.ts-lijst en vervolgens de grafiektitel.

dygraph(stocks.ts$TWTR$Close, main = "TWTR Stock Price") %>%
  dyRangeSelector(dateWindow = c("2013-12-18", "2016-12-30"))

basis-dygraph voor het aandeel van Twitter
Dit is een basis-dygraph voor het aandeel van Twitter

Een eenvoudige tradingstrategie: trendvolgend

High-frequency traders en hedgefondsen gebruiken geavanceerde modellen en regelgebaseerde benaderingen om transacties uit te voeren. Als je meer wilt leren, kijk dan op www.quantopian.com voor geavanceerde benaderingen. Voor eenvoudigere aanpakken begin je met deze pagina op www.Investopedia.com.

In de code hieronder visualiseer je een simpele momentumstrategie. In essentie wil je de voortschrijdende gemiddelden over 200 dagen en 50 dagen voor een koers berekenen. Op elke dag dat het 50-daags gemiddelde boven het 200-daags gemiddelde ligt, koop je of houd je je positie aan. Op dagen dat het 200-daags gemiddelde hoger is dan het 50-daags gemiddelde, verkoop je je aandelen. Deze strategie heet een trendvolgende strategie. De positieve of negatieve relatie tussen de twee tijdsgebaseerde gemiddelden staat voor het momentum van het aandeel.

Het TTR-pakket biedt SMA() om het eenvoudige voortschrijdende gemiddelde te berekenen. In dit codefragment bekijk je de eerste 6 waarden voor Twitter’s 200- en 50-daagse gemiddelden. SMA() werkt door de tijdreeksdata voor een aandeel en een specifieke kolom zoals Close door te geven. Dit is een enkele vector met slotkoersen voor het TWTR-aandeel. De tweede parameter is een integer die het aantal waarnemingen voor het gemiddelde aangeeft. Zonder head() zal SMA() alle waarden retourneren.

head(SMA(stocks.ts$TWTR$Close, 200))
head(SMA(stocks.ts$TWTR$Close, 50))

Nu je de moving-averagefunctie in detail hebt bekeken, moet je deze toepassen op elk van de 70 aandelen. stocks.ts is een lijst van 70 dataframes met individuele aandelendata. De vierde kolom van elk dataframe bevat de slotkoers die we willen gebruiken voor de gemiddelden.

De customfunctie mov.avgs() accepteert één dataframe met aandelendata om de voortschrijdende gemiddelden te berekenen. De eerste regel selecteert de slotkoersen door te indexeren met [,4] om stock.close te maken. Vervolgens gebruikt de functie ifelse om het aantal rijen in het dataframe te controleren. Concreet: als de nrow in het dataframe kleiner is dan (2*260), maakt de functie een dataframe met voortschrijdende gemiddelden met “NA”.

Ik koos dit getal omdat er ongeveer 250 handelsdagen per jaar zijn, dus dit controleert of de tijdreeks ongeveer 2 jaar of langer is. Loyal3 kan soms toegang krijgen tot IPO’s en als een aandeel net naar de beurs is gegaan, is er niet genoeg data voor een 200-daags gemiddelde. Als de waarde nrow groter is dan 2*260, maakt de functie een dataframe met de originele data plus 200- en 50-daagse gemiddelden als nieuwe kolommen. Met colnames geef ik de kolomnamen op. Het laatste deel van de functie gebruikt complete.cases om te controleren op waarden in de kolom met het 200-daags gemiddelde. Rijen zonder waarde worden in het eindresultaat verwijderd.

mov.avgs<-function(stock.df){
  stock.close<-stock.df[,4]
  ifelse((nrow(stock.df)<(2*260)),
         x<-data.frame(stock.df, 'NA', 'NA'),
         x<-data.frame(stock.df, SMA(stock.close, 200), SMA(stock.close, 50)))
  colnames(x)<-c(names(stock.df), 'sma_200','sma_50')
  x<-x[complete.cases(x$sma_200),]
  return(x)
  }

Met deze functie mov.avgs() kun je pblapply() gebruiken om de moving-averageberekeningen toe te voegen aan elk van de 70 dataframes.

stocks.ts<-pblapply(stocks.ts, mov.avgs)

Gebruik de code hieronder om de voortschrijdende gemiddelden van een aandeel te visualiseren met een dygraph. Ook hier wordt de operator “%>%” gebruikt om objecten door te geven. De functie dygraph() accepteert het dataframe stocks.ts$FOX. Specifiek wordt het dataframe geïndexeerd op kolomnaam met c('sma_200','sma_50'). Dit object wordt in de volgende 2 regels doorgegeven aan dySeries(). Je kunt naar een kolom verwijzen op naam, dus dySeries() plot elk een lijn voor de waarden “sma_50” en “sma_200” in regels 2 en 3. Dit object wordt opnieuw doorgestuurd naar dyRangeSelector() om de hoogte van de selector aan te passen. Tot slot voegde ik wat arcering toe om periodes te markeren waarin je het aandeel zou willen kopen/aanhouden en een periode waarin je je aandelen zou moeten verkopen of wegblijven, afhankelijk van je positie.

dygraph(stocks.ts$FOX[,c('sma_200','sma_50')],main = 'FOX Moving Averages') %>%
  dySeries('sma_50', label = 'sma 50') %>%
  dySeries('sma_200', label = 'sma 200') %>%
  dyRangeSelector(height = 30) %>%
  dyShading(from = '2016-4-28', to = '2016-7-27', color = '#CCEBD6') %>%
  dyShading(from = '2016-7-28', to = '2016-12-30', color = '#FFE6E6')

Hier is het eindresultaat in een interactieve tijdreeks.

fox moving averages
De FOX-voortschrijdende gemiddelden met gearceerde gebieden voor kopen/aanhouden versus verkopen

Conclusie

Als beginnende algorithmische trader hoef je niet alle 70 aandelen te plotten. In plaats daarvan wil je de code elke dag draaien en een programmatische manier toevoegen om aandelen te identificeren die passen bij de regelgebaseerde methode: “koop als het 50-daags gemiddelde boven het 200-daags gemiddelde ligt”. Als je naar de bovenstaande grafiek kijkt, is het groene gedeelte een periode waarin je het FOX-aandeel zou kopen. Het rode gedeelte staat voor de tijd om je aandelen te verkopen en niet opnieuw in te stappen.

Omdat de grafiek interactief is, kun je de schuifregelaar gebruiken om de weergave te vergroten of te verkleinen. Gebaseerd op deze eenvoudige algo-aanpak zou dit wel eens een goed moment kunnen zijn om FOX te kopen! 30 december 2016 was een handelsdag waarop het 50-daags gemiddelde $0,01 boven het 200-daags gemiddelde uitkwam!

fox-aandeel
Het ingezoomde gedeelte van het FOX-aandeel

Vergeet natuurlijk niet dat alle beleggingen in waarde kunnen dalen. Wil je meer leren over finance en algo trading, bekijk dan DataCamp’s cursussen hier.

Bekijk ook onze tutorial Basic Programming Skills in R.

Onderwerpen
R
Data Science

Leer meer over R

{count, plural, one {Cursus} other {Cursussen}}

Introductie tot R

{hours} uur
3.1M
Beheers de basis van data-analyse in R, inclusief vectors, lists en data frames, en oefen met echte datasets.
Bekijk detailsRight Arrow
Start Cursus
Meer bekijkenRight Arrow
Gerelateerd

{count, plural, one {blog} other {blogs}}

AI vanaf nul leren in 2026: een complete gids van de experts

Ontdek alles wat je moet weten om in 2026 AI te leren, van tips om te beginnen tot handige resources en inzichten van industrie-experts.
Adel Nehme's photo

Adel Nehme

15 min

Meer BekijkenMeer Bekijken