Rust has great libraries to make life easy, eg https://docs.rs/fixed/1.0.0/fixed/ (Note: I haven't benchmarked the 4 or 5+ fixed precision libraries Rust offers to see which is best.)
>All you need for algotrading is to query an api. Rust would be a poor choice for that anyways, like using a semi truck to carry your bike around.
That's not really true. It's more pulling from a database or csvs as backtesting is the most important part, which is also why the person you were replying to was asking about backtesting specifically.
Most firms roll out their own programming language, because before Rust existed there wasn't really a language that was a good choice for algo trading. Algo trading needs a few things:
1) It needs a financial number data type. That is, base 10 precision. Floats and doubles will not cut it when dealing with money.
2) The language needs to not implicitly do type conversions, so your types do not accidentally get converted to doubles.
3) You want provability. That is, you want guarantees that your program will run exactly the way you intended or you could lose a lot of money.
4) You hopefully want it to go fast, or backtesting could take ages. Historically super computers have been preferred, but that is probably not the case today. (This isn't even for HFT, just scalping and swing trading.)
Most in house languages in the industry are functional programming paradigm, because it allows guarantees. What you see is what you get. It allows one to write in a more mathematical way.
Today Rust takes the cake, as it is the only mainstream language that meets all the criteria, despite not being a functional programming paradigm language.
Performance is super critical in high frequency trading, so Rust sounds like reasonable choice. Having your code run a millisecond faster means beating out a competitor with the same algorithm as you, getting you a better price.
Be aware that Rust gives you the tools to be fast, it is not necessarily fast by default, although a lot of constructs it guides you towards usually help with that. You still need to profile your code to see what you need to optimize, whereas other languages with fewer knobs will perform optimizations that you otherwise need to manually annotate in your code in Rust. I prefer this approach, but it can be surprising to people used to the alternative.
Do you have examples of this? I'd be curious to know if so. (I've played w/ Rust a little bit -- I implemented a Boggle board scorer + high-scoring board generator; Rust outperformed my C++ code! I was impressed.)
These three different fn definitions have two different behaviors and affect both the speed of the code and the speed of compilation and it depends entirely on how they are called.
The first one is what the language calls generics: they are always monomorphized, which means that if you have three calls to `foo` with different types (that implement Trait) the compiler will expand three different functions with different types (code expansion).
The second one is a separate syntax level feature (impl Trait) which was mainly added to introduce a new feature which is static opaque types, where the function determines what the underlying the return type will be, but the caller can only interact with it using the trait's API.
[Aside] This is useful for cases like the following:
The more types you nest the more the benefits come into play. [end of aside]
Now, with that out of the way, the type of an impl Trait in argument is decided by the caller (not the function), so they are implemented internally exactly the same as type generics. The only difference is arguable nicer syntax in the definition and not being able to specify a type using the turbofish. For all intents and purposes, those two are the same feature.
The third function is different, it uses a virtual table, with everything that implies: there's type erasure, there's only a single function in the expanded code (which makes compilation faster because the compiler doesn't need to do work), calling this function can be slower because the final executable has to perform some pointer chasing to call methods, instead of directly knowing where to call them.
All of this to say: if you use `fn foo<T: Trait>(_: T)` or `fn foo(_: &Trait)` affects compilation and execute time, so you have to be aware of their distinction. This means that if you're not aware you might have slower code than you would with a compiler (like Swift, for example) which relies on heuristics to decide to do static or dynamic dispatch, but it also means that your code's performance characteristics won't change all of a sudden because you modified a tangentially related part of the code and suddenly crossed some threshold.
Another example can be `.clone()`: is it slow? The answer is always "it depends". You might be cloning an `Arc`, which is cheap, you could be cloning a 10MB string, which is slow. But because we train ourselves to see clone as slow we might be worried or annoyed by `Arc`. We could make it `Copy`, but if we did that then you have less control over where the `Arc` gets copied which would make it harder to keep track of where the RC gets incremented. The language also doesn't automatically implement `Copy` for small structs, even though it could, which would make it easier to learn that part of the language (you don't learn to add derives early on), at the cost of baffling behavior (you might add a field and suddenly your struct isn't considered "small" anymore).
Yet another example, you also have access to `Cow<'_, str>`, which lets you deal with both static and heap allocated strings in the same way in your code, but it pollutes your code, where the naïve thing to do would be to use `String` everywhere.
My personal wish is for Rust to remain explicit as much as possible, but use lints to emit suggestions for the cases where a more "magic" language would change the emitted code. That way the code documents its behavior with fewer surprises.
The monomorphization-vs-dynamic dispatch thing feels natural from a C++ perspective, as it completely mirrors the choice of achieving 'polymorphism' via templates or virtual methods (though of course the Rust syntax is way nicer!, using traits for both, whereas in C++ you have either a class definition or...nothing, just ungodly compile errors ("compile-time dynamic typing")).
That's interesting re Swift. It seems similar in a way to using heuristics to decide whether to inline a function or not.
I _think_ C# does monomorphization for value types ("struct") and vtables for reference types ("class"), though I wouldn't bet on it...
> fn it() -> impl Iterator<Item = i32> {
One of the things that impressed me w/ rust was being able to write really concise code using ".map()" and friends and finding that it all ended up running just as fast as raw loops.
(The thing that has most impressed me about rust was the crossbeam crate + type system + derive stuff, which let me parallelize board search in an incredibly easy fashion. I found it much nicer to work w/ than Go channels, which is supposedly one of Go's big tricks!)
I have no idea what you’re talking about. Rust is not faster than c or anything else necessarily that is not garbage collected. It is almost as fast, and it has memory safety and as is made apparent in this thread many advantages in terms of usability and undefined behavior. Being the quickest i s not something rust is known for. So you wouldn’t be saving milliseconds. And calling an api is pretty simple so the security aspect wouldn’t be of much use. So you are wrong and the guy you are responding to is right.
You would have to use unsafe and you'd be better off with C++. Also people who care about latency do not bother with the OS network stack. It's not a simple matter of picking language and magically going faster.
It's rare that I've run into such issues when using Python for building trading algorithms - most of the overhead (for me) seems to be building a strategy using the data that you have available. Numerical computing libraries such as NumPy, Pandas, and so on in the Python ecosystem make this much easier to do in Python.
I feel like static typing would get in the way there, making code more verbose and more difficult to prototype while running possibly thousands of backtests (e.g, to tune hyperparameters of your model) but if that your preference, by all means, Rust should be usable for that.
Rust has great libraries to make life easy, eg https://docs.rs/fixed/1.0.0/fixed/ (Note: I haven't benchmarked the 4 or 5+ fixed precision libraries Rust offers to see which is best.)