How do I do maths and print a result?

Work out the profit and return on a trade with R’s arithmetic, then round and format the answer so a person can read it.

R does arithmetic with +, -, *, / and ^, and brackets decide what happens first. What it prints back is a separate question: R shows 750, not 750.00.

In this lesson I work out the profit on one trade, then turn that trade’s return into a percentage a reader can scan.

Step 1. One trade in arithmetic

I bought 40 shares at 150.00 and sold them at 168.75.

buy    <- 150.00              # what I paid per share
sell   <- 168.75              # what I sold at
shares <- 40                  # size of the position

print(sell - buy)             # -> [1] 18.75
[1] 18.75
print((sell - buy) * shares)  # -> [1] 750
[1] 750
print(buy * shares)           # -> [1] 6000    <- what the position cost me
[1] 6000
print(sell / buy)             # -> [1] 1.125   <- every 1 became 1.125
[1] 1.125

Without the brackets around sell - buy R multiplies before it subtracts.

print(sell - buy * shares)    # -> [1] -5831.25   <- buy * shares happened first
[1] -5831.25
print((sell - buy) * shares)  # -> [1] 750
[1] 750

* and / run before + and -. When you want a different order, say so with brackets.

Step 2. Powers and remainders

^ raises a number to a power. Growing 8% a year for three years is 1.08 ^ 3, and the reverse, the annual rate behind three years of 8% total growth, is 1.08 ^ (1 / 3).

print(1.08 ^ 3)               # -> [1] 1.259712   <- 8% a year for 3 years
[1] 1.259712
print(1.08 ^ (1 / 3))         # -> [1] 1.025986   <- 8% over 3 years is 2.6% a year
[1] 1.025986

%% gives the remainder after a division and %/% gives the whole part. Splitting 40 shares into three equal tranches leaves one share over.

print(shares %/% 3)           # -> [1] 13   <- shares per tranche
[1] 13
print(shares %% 3)            # -> [1] 1    <- shares left over
[1] 1
print(shares %% 2)            # -> [1] 0    <- 40 splits evenly in two
[1] 0

A remainder of 0 means the division came out exact.

Step 3. R drops the trailing zeros

The profit is 750.00 in money, but R prints 750. It shows the shortest form of the number and stops there.

profit <- (sell - buy) * shares   # 18.75 a share across 40 shares
print(profit)                     # -> [1] 750   <- not 750.00
[1] 750
print(profit / 7)                 # -> [1] 107.1429   <- cut short on display
[1] 107.1429
print(round(profit / 7, 2))       # -> [1] 107.14
[1] 107.14

round(x, 2) keeps two decimals. It changes the number, not just the display, so use it when you want the value rounded and not before.

print(round(1.08 ^ (1 / 3), 4))   # -> [1] 1.026   <- asked for 4, printed 3
[1] 1.026

I asked for four decimals and got 1.026. round() cannot force a trailing zero, because 1.0260 and 1.026 are the same number. For a fixed number of decimals on screen you need Step 5.

Step 4. The return as a decimal

A return is the sell price over the buy price, minus 1. Store it as a decimal, always. 0.125, not 12.5.

ret <- sell / buy - 1         # holds 0.125
print(ret)                    # -> [1] 0.125
[1] 0.125
print(ret * 100)              # -> [1] 12.5   <- the same return in percent
[1] 12.5
print(round(ret * 100, 2))    # -> [1] 12.5   <- still not 12.50
[1] 12.5

Decimals are what the arithmetic in later lessons expects: 1 + ret is a growth factor, and 0.125 gives 1.125. Percentages are for the last step, when a person reads the number.

Step 5. Format it with sprintf

sprintf("%.2f", x) builds text from a number with exactly two decimals. The %.2f is a slot: f means a number with decimals and .2 means two of them.

print(sprintf("%.2f", profit))         # -> [1] "750.00"
[1] "750.00"
print(sprintf("%.2f", ret * 100))      # -> [1] "12.50"
[1] "12.50"
print(sprintf("%.2f%%", ret * 100))    # -> [1] "12.50%"
[1] "12.50%"
print(class(sprintf("%.2f", profit)))  # -> [1] "character"
[1] "character"

%% inside the quotes is how you get one literal % on the end, because a single % starts a slot. And the result is "character", text, not a number. Format at the point of printing; do your sums on the numbers.

paste0() glues pieces together with nothing in between.

line <- paste0("bought at ", buy, ", sold at ", sell,
               ", profit ", sprintf("%.2f", profit))
print(line)   # -> [1] "bought at 150, sold at 168.75, profit 750.00"
[1] "bought at 150, sold at 168.75, profit 750.00"

buy came out as 150 because paste0 converted the number the same way print does. The profit kept its two decimals because sprintf had already turned it into text.

Step 6. print and cat

print shows you the object: a [1] prefix, and quotes around text. cat writes the contents out raw, and adds no line ending of its own, so you supply "\n".

print(line)      # -> [1] "bought at 150, sold at 168.75, profit 750.00"
[1] "bought at 150, sold at 168.75, profit 750.00"
cat(line, "\n")  # -> bought at 150, sold at 168.75, profit 750.00
bought at 150, sold at 168.75, profit 750.00 

cat also puts a space between whatever you pass it, which is why "\n" sits as its own argument.

On a vector the difference is bigger. Three daily returns, stored as decimals and shown as percentages:

rets <- c(0.0125, -0.0038, 0.0207)     # three daily returns, as decimals
days <- c("Tue", "Wed", "Thu")         # the day each one belongs to

print(rets)                            # -> [1]  0.0125 -0.0038  0.0207
[1]  0.0125 -0.0038  0.0207
print(sprintf("%.2f%%", rets * 100))   # -> [1] "1.25%"  "-0.38%" "2.07%"
[1] "1.25%"  "-0.38%" "2.07%" 

sprintf ran down the whole vector and returned three strings. cat with sep = "\n" puts each on its own line:

cat(paste0(days, "  ", sprintf("%.2f%%", rets * 100)), sep = "\n")
Tue  1.25%
Wed  -0.38%
Thu  2.07%
# -> Tue  1.25%
# -> Wed  -0.38%
# -> Thu  2.07%

Your turn

I bought 25 shares at 40.00 and sold them at 46.50. Work out the profit and the return, keep the return as a decimal, and print one line reading profit 162.50, return 16.25%.

buy    <- 40.00                     # price paid per share
sell   <- 46.50                     # price sold at
shares <- 25                        # size of the position

profit <- (sell - buy) * shares     # brackets first, then multiply
ret    <- sell / buy - 1            # kept as a decimal

print(profit)                       # -> [1] 162.5
print(ret)                          # -> [1] 0.1625

cat(paste0("profit ", sprintf("%.2f", profit),
           ", return ", sprintf("%.2f%%", ret * 100)), "\n")
# -> profit 162.50, return 16.25%