Full Transcript
Welcome to part three of let's build a quant trading strategy. In this video, we're going to be focusing on the implementation. In the previous videos, we looked at part one, which was the research, which was to uh to build a model that takes an input and it makes a a prediction. And then in the second part we looked at using that prediction putting it into a strategy and then that strategy generates orders and then the the orders are then executed uh onto an exchange. So we've already covered this uh but I'm going to do a recap just in case that you haven't watched part one or part two that you can easily follow this independently. So the key goals for this is to to to code it all together in Python. So essentially we it's like uh cooking. We've got the ingredients. Uh we've got the recipe. Now we just need to to put it all together. So we're going to say how to to gel the model and the strategy together and how to to stream data into it. So ideally it would be n better to to do it in a statically typed language like Rust but we're just going to use Python because this is the most uh basic language just to to to code with and also because all of our research so far has all been done in Python and then the other goal is to show how to build a trading system in a scalable way so that it's like you can easily create new strategies so we'll look at like building a strategy API and also how to stream the data. So, we're not going to look purely on like just on the high performance side because uh that could be a video separately by itself. Uh but yeah, we then we're going to put it live with real money and to see how it performs. So, that'll be the next video probably. We'll connect it to an exchange. We'll use some real money just just a small amount and we'll see how it goes. And even if for example the performance starts to decay which is called like model drift or alpha decay then we can learn from this and we can see like okay what do you do if your model stops that the the pattern is learned is not persistence anymore. So yeah even so yeah even if the if we put it live and it starts the performance starts to decay we can have a look to see why it happened and the solutions to it. So now let's go into uh a recap. So let's write this down here. So now we're going to do a recap. So in part one we looked at the the research part and in the research we built a mod. We we've we iterated and built a a model. And in the model, so I'm just going to Oops. So in the we've got our models and we've stored them in this file called models.py. And then we're going to import our machine learning library torch. And we're going to import the research API. And the research API is just uh an internal API that I've built just to remove a lot of the boiler plate uh pertaining to research. And then we're going to in instantiate the the model because I just want to show you the model that we built. And so there was three features to the model. And then we're just going to load the the parameters from from disk. And so we do torch.load models and it should pick it up. Yeah. And we also it's very important to to pick this uh weights only equals true because this just ensures that it doesn't run any arbitrary code that could be a a d could be quite dangerous to run some arbitrary code. So uh it's very important that you pass this as true. And then we're going to put it in evaluation mode. So this makes sure that any layers that are just strictly pertaining to to training is not run. So for example like here it says here like dropout uh so it won't run this but because ours is a linear model that we don't have any of this but it's just in when we like for example if we go to neural networks then yeah we want to make sure so it's just very good practice. And so now we're just going to run this. And you can see here this input is three and the output is one and you've got a bias. So this is a linear model. And specifically what we've built is is what's called in econometric is a auto reggressive free model and that was to predict and so it's to predict the future log return with a 12hour forecast horizon. Okay. So and I'm just going to to show what the the parameters of this model. So now we do research print model parameters. We're going to print the model and we're going to see the the parameters. Uh and and the beauty of linear models is that they have great u interp. So for example, we can see that that the first two lags, the most recent lags uh have a negative coefficient or negative weight. So this can uh imply a mean reversion, a weak mean reversion pattern here. So this is essentially what this model is modeling is a mean reversion. And now so that's the the recap of the first video. So I've just saved you like two hours there. And to save you another two hours, I will now just recap on part two. Oops. And so with part two, we're looking at the the strategy and we made like there's two key decisions there and I'm just going to go over them. Okay. So the the first part was like for example we just without any optimizations we we we we it was it came to like 14% was the the original like uh so just going to put this here it was roughly around about I think it's 14.4%. uh and without any optimization and then we looked at like two key decisions that essentially were optimizing the strategy. So for example we used uh what was called the first key decision was compounding trade sizing and essentially what this was doing was uh using all like for example if if our trade made let's say we started with $100 and it made $5. So then the next trade uh would would open a position with $105. So it's just reinvesting the money uh into for the next uh position. So and this was because you're essentially compounding. So this is the the first key decision. And then the second one was that we used leverage and that's essentially where you're borrowing money. Uh so this can amplify your profits but it can also amplify your losses. So it's very important that you use this with an edge. And then by using these the these two we it it turned the returns from 14% to over uh 40%. I can't remember how much roughly it was but it was like over 40%. And the reason for this was because of of the the leverage the compound trade sizing and the model's edge. So all those three together uh produce these like a phenomenal increase in the returns. So that's the that's the strategy recap. So I think we're all ready to to start on part three. And so I've saved you over four hours there. Uh so now we're going to go over the the the fundamental building block which is this. I'm just going to maybe fundamental building block. Just like building a house, there has to be like a foundation. So our foundation is what's called a what I call is a tick. And the tick is I'm actually just rather than it's not I'm just going to copy and paste it to save time. explain that okay so this is uh an abstract class so it doesn't have any implementation I expect whatever extends this class is to implement this method and it's essentially like how do you handle new data coming from the exchange so this could be like order book data coming in this could be a trade feed it could be just I don't know some just a generic open high low close pricing time series. It's just like when there's a new information or new data uh what should it do and it's like how you like event handling essentially. Uh but don't worry if this doesn't make sense and also this is important that it's uh uh generic. So it has this thing called polymorphism. So rather than hardcode it to specific types that it's and like for example having a tick I don't know float tick or a string tick or decimal tick that it's completely generic. So you don't need like to code up specific implementations. Uh but don't worry if this doesn't make sense because hopefully later on this should make sense. So that's of essential building block is this tick class. And then the fundamental data structure is the sliding window. And the sliding window essentially memorizes the most recent data points. So if imagine like you you're millions of trades were coming in and you just may be only interested in like the the most recent ones. You don't want to store like all let's say you got 10 million in a day or 10 million. you're just interested in like the the last I don't know the last known 20. Um so it's a bit like you know Netflix how they stream movies. They don't just get you to download like uh 10 gigabyte movies straight away. They they stream it as you watch in. So you just they just download the data just in time for you to uh to watch it. And it's exactly the same here. We're just streaming the data in uh just in time to make decisions. So now this is the fundamental data structure. [Music] I'm going to put this in markdown and uh rather than me just code it, I'm going to just copy and paste it to save some time. Okay. So, and so essentially the the data structure behind it is what's called a double-ended Q. Uh this allows you to insert at the front and at the back in what's called constant time. Uh like for example, if you ever heard of bigo notation, so this is basically it scales like constantly regardless of the the size of the of of the data. Uh so it's just allows it to be more efficient than using an array. Uh we don't need to get bogged down into the details. But I recommend to have a look and see how it's actually imple implement. I also feel to get better at coding you should try and implement some of these like fundamental data structures because that really helps you to give you a better understanding of the underlying data structures. So essentially the key important thing is that uh it's called a DQ window because it's the the it's using a DQ and it's still generic because we're just saying that the input is T and we're saying that the output is an optional of T. So this optional essentially is saying that it's either going to be of T or it's going to be uh none. So for example if you've used rust this is equivalent or hasll this is equivalent of option so but it's this doesn't have the algebraic data types but anyway this is so on you've got dropped and yeah so when it's full we drop uh the data point at uh 0 and then we append the new data point into it and then we we return the drop just in case whoever uh the the client is calling this that it can handle if it wants to like know what what was dropped and and then this is just boilerplate code and just another important part is that we can also pend so it'll pend it to uh the right but you can also pend to the left so that's the front of the queue and that's quite important to us later on but uh we don't need to um to know for now. And then yeah, for example, we want to convert into a numpy uh but we'll explain that later. So that's the the core of the uh this DQ window, but it'll make more sense if we actually just run a few examples. So here are a few examples. So let's just say we create a window of of uh three. So it has a capacity of of three and is empty. And now what we're going to do is to create like just for example again but we're just going to do on tick. So let's say a data point comes in and just see what happens. So see here it's it's stores as one. Okay. But now let's see what happens when we let's say there's again still DQ window and this time we're going to call on tick one two three oh and then we going to to print W. So you see here it it stores it. So that's ju just behaves like as like an array would right. Uh but now let's just say that we're just now going to uh append four to it. So you see here uh one has now been dropped and if we wanted to keep one then we would store this as a local variable from here. Uh and you can see now it's still capacity is three but uh the one's removed and we've now just appended four and it's uh it's at the the end. So that's essentially how it works. It's it's called a sliding window. And yeah, so now what we can do is I just want to show you just another example which is like for example uh let's do this [Music] So as you can see it's just like it's like a memory. It just only memorizes the last known values and we're saying like we want to memorize uh so you can see here like what it's doing. Uh, and so now what I want to do is to to show so that was a DQ and you may be guessing well we can just use like a a normal array based window and I just want to because what we'll do is we'll implement it and then we're going to do a performance benchmark and see which one is faster. So for the array base window, I'm just going to rather than because I think it would be very boring if I just code this is I just take this code. Uh it's pretty much the same apart from that we manually are shifting the the values in the the array, but it's pretty much the the same. And rather than just So now what we're going to do is we're going to benchmark the numpy window or the array window versus the DQ window. And uh what I'll do is I'll just maybe just copy and paste this code. So that's the the the functionality to do the benchmarking. So now what we're going to do is we're going to is to benchmark. We're and I also want you to maybe let's look at the results and see which one is fastest. And I would love you to to write in the comments what you why you believe um the other is faster that one is faster than the other. So, first we're going to do that for the array based window, pardon me. And then we're going to do it with the DQ window. So, that took 5 seconds. So, now let's see if DQ is going to be faster. So, let me just show the the implementation as well. So, numpy is is an array. So it's a contiguous memory allocation whereas DQ is a linked list which is non-ontiguous. So uh it's it allocates memory different has memory. So it's not all in one line. It's not inline memory slot. So now let's run this. So you see here it's it's much faster to use the the DQ. uh and maybe if you put in the comments why you believe this uh it is I think I've already given some hints anyway in the but uh yeah so and another important thing is to stream like the last known value [Music] the last known value so for example we want to track the the for each time interval uh we want to track the last known trading price uh and to do this we need to aggregate the last name value and it's quite easy to to code up. Um, one I'll do again is I'll just copy and paste our code. So, this is essentially it. So, we're I don't think we we we need this generic t but I think sometimes sometimes the llinter complains. So we have this the most important thing is that we're extending uh uh tick and to to extend tick we also must implement on tick uh method. So essentially what it's doing is we're storing this optional of t we're setting it to none and then once a tick comes in we just update it and also return it as well. Uh that's not true and that's so that's That's that. And I just want to just show an some examples of this now. So blast val last the the constructor is empty and we're just going to print it out. So it sets it to none. And let's just do this. We'll just iterate just let's say five times maybe. So you see here the last known value is four. Uh it starts from zero. So so again it's quite trivial but uh it's just important to be able to stream the last uh uh known trading price. So now what we want to do though the is to stream oops is to stream log returns. So we need to build uh prices to build the log returns and then we'll take the last three known log returns and pass that into our into our model. So we're going to do streaming. Oops. I keep on pressing streaming log returns. And just I need to give like a a recap first of of this. So we just quickly do a quick re recap of what log returns are. So log returns. So let's start with an example would be best way. Okay. So for example, if like just use the same example that I used in the previous uh videos. So for example, if we have a time series a price time series and it goes it starts at 100, goes up to 120 and then drops back down to 100. Uh if we calculate the log returns for this, then it's essentially this. this log time series 1 over time series at 0. Then we're interested in the second index. So that will calculate the log returns of this price time series. um we also want to to print it out. So you see here, so the beauty of log returns is that they're symmetric that you can add them up and that gives you your net return position. So if we add this up, then it's a sac for example, if we took the deltas uh the price difference between them and add them up, then you would get 100 and sism with log returns. If you add them up together, you get the the total. So for example just to to make it very clear uh if I do sum of log returns and this is the the the the property is called time additivity. So and then we add them up we get to to zero and so now we have an understanding of log returns. So now let's stream log returns. So we we need to from the yeah actually maybe if it's even easier if I show you. So we take the log return. This is essentially streaming log returns. Uh so we're using uh this is an important detail is that we're going to even though it's just a window size of two but it's just easier because we can access the so we want to access it like this. Uh it just makes it easier to uh uh to access the elements. So essentially what it's doing is that once it's full as in there's two we've got two prices to calculate log return we calculate the log return. Uh but we always like update it. So we drop like the the oldest value. Uh so and yeah so that's how the log returns are calculated. But just to make it more concrete let's show an example. So what we're going to do is Our streaming function is this log return. We're going to call on tick 100. And we're just going to print out to see what it looks like under the hood. So you can see here we've got a capacity of two. The size is one. And you can see in the array we just have one element uh 100. So so far so good. And now what we're going to do is we're going to say 120. We're going to print the value out. So you see here it's now generated the log return. So, so from 120 uh from 100 to 120, you can see it moved up by $20. And that's roughly uh 18.2 in log space. And now if we look at the under the hood, you can see okay that it's calculated from this array here. So now if I want to now calculate the other way now. So, for example, uh let's just call F on tick. So, in our price, we went back down to 100 and we're going to print out the value. So, it should just be the the negative of this. And you can see this here that it's uh now it's 18. So, and then if we have a look and see what's going on under the hood again, you can see that this the oldest value has been dropped. And now that value has moved over to this side. And then 100 which is the most recent price uh is at the end. So this is how it it streams log returns. So it's not click like an array of 1 million prices and then just take like the last two. It it just streams it intelligently. So uh that the memory is always of a constant size. So that's now that's log returns but we actually want to pass into our stream what's called maybe I put this down. So what we want to do is to stream [Music] auto what's called auto reggressive log returns lags. So the the lags are essentially the previous values in the time series and I'll also do just a quick recap as well uh what they are. So the recap if I just put a recap here [Music] because I appreciate not everyone has watched part one and part two but just maybe interested in just the the coding side. So for example, let's say we have a time series and let's say it's just log returns and know say minus0.2 and then the most recent is always on the right and then the oldest on the left. Okay. So for example, if I call if if you hear me say lag one, what essentially what I'm saying is the most recent uh let's say this is the the current values and we want to predict in the future. we don't know what that that value is. Uh so this is lag one. So I'm just going to make that explicit here. So when when you take a a negative index, you you're flipping it to say okay the first element from the the back. So for now you can see it's minus three. Okay. And then for lag two, it's just time series minus two. [Music] and then 01. Okay, so that's lags. So if you hear me say like lags or auto reag. So now we're going to look at the the coding of it though. And so to do this, I think it'll be quicker if I just copy and paste the code and go over it. And again we're just uh extending the tick class because we want to implement on tick. Uh and the key in the constructor the key thing is is the number of lags that we're interested in. Uh so we're saying here that we're interested in an arbitrary amount and then that's where we create create the dq window. Uh and then we've got the log return aggregator. So this streams the log. You've seen it before, but it streams the the prices and generates log returns once the the windows filled up. And then we just generate uh call log return on tech. This will either be none or actually have a uh a log return. So this is what we check for and uh if there is a log return then we append it to the lags uh dq window. And then when it's uh we append it to the left and we so this is a key. So we generate a torch tensor uh because our model is in pietorch and it works with tensors not arrays uh or numpy arrays. But what we do though this is a key important detail is that we pass in a numpy array. And the reason for this and not just say like a python list is with numpy it can do what like a zero memory copy. So you can allocate the memory as a numpy array and then pass into tensor and it doesn't create a copy of it. It just does like a a memory swap essentially. So it's like what's called like a zero copy. Uh so that's essentially why I implemented this into numpy. Uh and then we only do this if the lags is full else we just return none. Uh so but don't worry if you don't understand what this is doing because we'll again we'll just use some examples to build the intuition. So what I'll do is I will so you see here on the first tick it's say $90. we add it to the log return window, but it doesn't generate a log return because the the window is uh not at full capacity yet. So now let's just do now let me just easier if I just copy and paste again. So now we're going to run it again. And you can see now that it's generated a log return because it's now got two two numbers to to do it. And it's now added it in our DQ window. But it hasn't returned this hasn't returned any because it needs it's not a full capacity yet. So we haven't got enough features yet. So this just to make it clear. So this is the features that's passed into our into our model. So uh and now what we're going to do is just to keep running this until the the window is full and it can we actually can pass it to the model and we're just going to do it explicitly here. But when we build our strategy uh this is what our strategy is going to be doing. So if I now run this now you can see now we've got two. So on on the the next one uh it's going to generate uh the tensor. So and we can see this here. So if we run and these are log returns by the way. So and it's already got into a tensor. So we can pass this into our into our model. And just to to show you what it's doing. So maybe if I just show you the like the C the math behind it. So [Music] this is the equivalent of of this. You just remove that. So that's essentially what it's calculated but it's doing it uh while streaming pricing data in. So uh another just maybe show another example just all all together. So if we're going to create the the the features is let's just run this. And now I just want to show like streaming the the now we're going to do is stream features into our model. So we we we've called this features. We're going to we can call them X which we'll probably do just to make it more uh explicit. So we've got the features uh and when remember from the previous lessons that when we uh we don't want to um we want to run it in no gradient. So that disables gradient calculations because we don't need it for inference. So then yhat equals model of X [Music] And then it's made a prediction. So it's made a prediction here that it's going to go down. And just from in from a superficial look, we can see that because the uh our biggest weight is at lag one. So this strongly influences the this lag one strongly influences the the inference. So now it's made the the prediction and but this is uh comes as a one-dimensional array and we want to to get it as a scalar. The scala is essentially just like a single value. So we can then just do y hat zero. So now we've got it. It's still a tensor but we can convert this back. We can detach it. Maybe it's on the GPU or or on the CPU. We detach it and we can put it back into uh uh to be used. And now that's the streaming functionality of our trading system. And so now we're going to can go focus on the architecture and actually building the the system. So we're going to do build the trading system. So I I just wanted to show you the the streaming functionality of the system. And another really key important lesson is the using decimal to represent money. So I'll make it as a headline as well. Using decimal to represent money and to build the intuition to explain why it'd be better if I show an example. So maybe if I just copy and paste this code again. So essentially, let's just say like we're in loop and we're adding up. Let's say we make 10 cents every time and we want to add up. So it should add up to 1.0. But if we run it, it doesn't. Uh uh so and we we need this accuracy for to represent money because like imagine like having small errors like this and they compound and then your the calculations become way off. It's like a butterfly effect. So the way we can get around this is by using decimal. And so now if we do exactly the same you can see now it's 1 zero. So it represents the the accuracy correctly and it's using something called like fixed point precision. Uh so this is it's important to uh to understand this. So now we need to create some like data classes. Uh so the first one we need to do is and I'm going to copy and paste because it's it's quite trivial. is our order and then the next one we need to do. So this is represents an order that we send to the exchange. Uh an important detail is obviously the symbol which is what we want to to buy or sell but uh we're going to encode the direction and the the quantity of the order in one variable. So if it's negative then we're saying we want to go short. Uh and if it's positive we want to go long. So it's just saves having another variable saying is long or is short. Uh then uh I just like to encode it into just into one. So that's our class. And now what we want to do is to create a trade class. And again we're just going to copy and paste. So it's quite uh don't there isn't uh in the ap the decimal class there isn't a method to to get the the sign essentially if it's one if it's positive or minus one if it's negative. So I've just written some some functionality to to do that. Uh and then so it's just pretty much the same as the as the order, but we have a price that it traded at uh and uh the P&L. So for example, if this was to to open a trade, then there's no associated profit with with that trade because it's just opening a position or uh increasing the position size. But when we start to close or reduce the position, there's an associated uh profit or loss with the trade. So, um it could either be none uh or or zero, sorry, or it could actually have a value associated with it. So, that's the the trade class. And now what we want to do is create a position class. [Music] And with the position class and again it's just uh it's the same and this this is just a very basic representation because for example uh it could be there could be you need to monitor the average price for example you don't always the position could be traded at different you could have trades at multiple different prices and sizes and you need to uh to to calculate uh like an average position price. Uh, another important is this method called unrealized P&L. So, this is also called mark to market. So, it's like saying if we close our position, how much profit would we make uh if we close it right now? And if we do close it, it's called like a realized P&L because we've actually realized that that uh a profit or a loss. Uh so we just call this unrealized but this is also you might hear this be called mark to market. And then to calculate it we just have the calculate the notional value at entry and the notional value at exit. Uh and yeah then that's our unrealized P&L. And we're just going to run this. So that's the the the data classes. Uh, and now what we need to do is to create a base class for account management. So when you have an account, you need to know what the balances and be able to get like positions. So uh, and this is just uh there's a lot more methods that you would need, but I'm just adding the most basic just to to show as an example as a as a base. So yeah. So that's and again it's an abstract method with Uh so uh if we extend this class for example we can have accounts for different let's say Binance uh or different exchanges and even just let's say brokers for example Awanda uh I don't know other ones but uh yeah so we or interactive brokers uh so this is like our base place base class to to extend from and what we're going to do is just create a test dummy uh account just to as a mock. So to do this we maybe we're going to do this. So maybe I just go over the the details here. Don't need this. So we have a balance. We have positions which is uh the direction our trade is in our trades are in. Uh and then this is the individual trades. So we can see the trades that opening the trades that closing and then we have this actually we don't need the this counter and then we implement the balance the and implement this get position. And here's a key important thing. So for example, if we use the index access which you know the brackets uh and it's not there then it throws an exception. So I'm going to use this get because then if it's not found then uh it just returns none and this complements uh because our return type is like optional position. So that's our test account and just to to show example of how to to use it uh I'm going to run it here so you can see like okay if I start uh with humble a balance of $50 then uh you can see here that we call balance it's 50 and then for example if we now see this you know see the we've got no positions and we've got no trades. So now what we want to do is to create uh an abstract class or interface for an exchange. So this is what we're going to do now. So model do this model ex and exchange and I'll just again just copy and paste the code. Uh the key important uh difference here is that we are extending account. So because for example in some uh parts of a code we don't want to expose the ability to to to create an order either a market order or a limit order. We just want to say okay you can access the only the the balance. So it's just a bit more dangerous if for example if we pass the exchange because we don't want the strategy to actually execute any orders. We just want it to generate some like orders. So then the next layer can then run the orders. Uh so it's just a good practice really. So and then this is the exchange and then there's just obviously there's a few more uh for example you would want to to send be able to have the ability to send multiple orders at once. Um but just for simplicity then I've just kept it to just to to singular orders. But in reality, you would you have the ability to to send multiple orders and all different sorts of order types. And now we're going to create like a a mock test exchange. I'm just going to to copy and paste the code here and then maybe just go over. So, uh here's another key important detail as well. So, pardon me. This is uh like a design pattern called composition over inheritance. So rather than extend the test account uh I I'm now it's now composed. So rather than using inheritance I'm just using composition instead. So I pass in the account and then I just for example here for balance I just delegate it to uh to balance. Uh the key functionality here is the market order. So, we're not going to go over limit orders because we don't have any level three order book data and it will just increase the complexity of this uh tutorial. So, the key important thing here is just like we're just mocking like uh how an exchange creates and closes ex uh positions and balance. And so, it just updates the position based on the the trade. uh and if there's uh if it's to reduce our position then there's an associated profit and loss and then we use that to add to the the balance and then we just append it to the trades. Uh so but yeah that's the main and then yeah if it's um yeah we won't go into more if you're interested you can look into this more further but this is just a very simplified version of it. And I just want to show you now like how to create positions in the test account like the difference because you may not know what the difference between like a trade and a position and it would be really clear if we show an example. So this is what we're going to do now. And we're going to do test exchange. And then we're going to pass in test account decimal 50 decimal 10. Quantity decimal 5.0 zero exchange and then call decimal price. Okay, so we're going to pass a market order with a price and known quantity. Uh so obviously when we send it like in a in the real world we would not say like create a market order with a specific price but that could just be uh just um so we're just using this purely just for uh testing purposes really just to but uh I think I should make this none but this is just to give an example because uh that's the last known traded let's say that's the last known traded price but you that's what you you would expect the price to trade but it doesn't always because the price could change right and that's what's called like uh uh slippage u but yeah anyway this is just like a so anyway so now we've run the the trade and you can see here's that it's It's a positive. You see the sign quantity. It's a positive number. And so that means that it's it's gone long. And uh that's the price it traded at. Uh it could have deviated, right? So it could have like the price could have moved and it could have like been 9 or 11. And because it's opening a position, there's no associated pier now because we're it's not reducing or closing the position. So that's that. And now [Music] I want to just show you the exchange now. So exchange the balance is still 50. Uh but see here it's now got a position and that's the position. Uh so it's a long position. It's the price is at 10. Uh and then that's the the trade it at. And I just want to show now like for example closing this position because the our strategy what it does is at the beginning of a time interval it it opens a position and then after 12 hours at the end of the time interval we close the position and open up a new position. So I just want to explicitly do this manually but automatically we will want the ability to to do this. So uh so now we're going to close it. Maybe if I just make it clear as well. So, we're going to close the position. I made Did I say this open position? Okay. So, let me just make this clear that this was open position. Okay. So what we're going to do is we're going to close it down altogether. So let's say the price has gone shot up from 10 to 15. And so we want to take the flip negate the quantity, right? So flip it to turn around. So from positive 5 to minus 5 and that will close the position. we we will see this. So now we're going to run it. So you can see that the the signed quantity is minus five because we're now going short by five and that's the price it traded at. And you can see now because it's reducing or in our case actually closing the position in full. Uh there's an associated P&L with it. So it's saying it's made $25. And now if we look at the exchange, we should see that. Oh, let's have a look at the exchange. So you see here that the position is now empty. And now we've got two trades. One was to open and the other one was to close. So imagine like we're at the end of the time interval uh and we close the position, but at the same time we also want to open a position. So uh ideally uh we open and then we then the next trade straight afterwards is to open a new position and I also just want to show how it was calculated uh the profit. So for example we have the entry notion notional value which is essentially we we the the the number of units we bought at the price and that's 50 right because we had uh our count had um did we say this? Yeah $50. Uh so that's the and that's the entry size or notional value. And now if we look at the if I just copy this in. Now if we look at the exit notional value that's the price that uh our trade closed at. So then you just take the the delta of that and then you can see that this is how it this is the maths of uh how it calculated it. So that's 25. But wouldn't need to do this is just for uh testing and educational purposes. If we were like connecting exchange, they would have like a a test environment where you can actually uh code this and get the the position. So you don't need to manually manage the positions yourselves. You may there may be some cases where you need to want to manually manage and keep make sure it's in sync with the actual markets state. But uh for our purposes um yeah we're just going to this is just like a mock exchange. And so a really important uh decision like in terms of building the system is like our API design. And we're going to now start building the strategy API. We want to design the strategy API in such a way that it makes it super quick and easy to build a new interface. We don't have to copy and paste lots of code. we just need to extend like a base class and it takes care of all the nuances of connecting to an exchange and sending orders and so that's what our class is going to do and we're just going to keep keep it very basic and we can build upon this. So our strategy notice it hasn't extended tick because um we also on the tick we also because we're going to use compounding uh trade sizing that we need to know what the balance is and we don't want the and I don't want a class every class to uh pass in an account because it may not want need it. So it's just so it's it's like our tick class, but it's just got an additional account parameter. And so the return type is uh an optional. So it's either going to be uh none, null, or it's going to be a list of orders. And the orders, it's either going to be just an order to open like to open a position, but it could also be a list of like two. It could be one to close the existing position and then another order to open a new position. Uh but we'll show it in detail later. So now what we want to do is to create our actually implement our strategy. Now put this mark down. And so essentially what we're going to do is to extend our class. Oops. I'm going to put this back into Python. There we go. So rather than I I I'll go over all the code. So in the construction, we're passing in the the symbol. We're passing in the the model. And the model uh if we can have a look here you can see look the base class for all your neural network modules but we're just using a linear model right and then we want to need to stream we're going to get like a stream of prices coming uh and like in 12-hour intervals for for us because it's uh we're predicting 12 hours ahead always. So at each 12-hour interval, we're going to get a new price, and we want to stream this into our log return ls. And this is the scale factor. So for example, this tell um at the moment we're just going to treat it as a constant, but this could be dynamically adapting. And this is essentially if we're going to use leverage, but it could also be the opposite. So it could say like we don't use all our capital, we only use like 10% of our capital. dependent on uh yeah on how much our risk tolerance is. So that's the as you can see here and then if it's it's an optional so if it's optional then it's just going to say that the scale factor is 1.0. So it's going to use all the the capital uh that's available uh in the balance. And so maybe if I go to on tick that would be the so when it gets a new price as in there's a new time interval a new it's 12 hours of pass and there's a new uh price then it's going to pass it into log returns lag. We've seen how this works. So this is the the features for our model which we denote as X and if X is is not empty then we run we pass into the model we that's our prediction right and this is yeah so this is the model and this is creates the orders. So uh it passes in our prediction and the account and the the price um it trade it like the essentially mocking the the trading price and that's the the the orders it generates. Uh and just a really key important detail maybe is here. So this is where it creates the order. So if there's already an ex existing position then it returns two orders. One to close the position uh and another order to open a new position. But if it's running for the first time or also not first time but if there isn't an open position then it's just a singular order just to open the an order to open have an open position and yeah then that this is the signed compound trade size but um if you're interested then uh I' you can study this code. So that's the strategy, right? And I just want to show you like how the day the strategy streams prices in and to generate orders. So let's so we this is all the the components of our strategy that we pass in, right? And on the first let's say this is the first 12-hour interval uh we pass in we call on tick and we pass in let's let's just say the you know this is not an authentic price of the genuine price of bitcoin dollar but just say for arbit it's $10 right so it doesn't generate any orders because it hasn't filled up enough data in our window but in production you would not do this because you couldn't wait like uh for like uh over a day and a half to to get the the the latest like lags. So in in in a real production system, you would get the the the prices and already populate it before it actually starts to to trade, right? So it doesn't have to wait because imagine like if the it was like the forecast horizon was like uh week instead of instead of hours like 12 hours it was a week right so then that you would have to wait uh three weeks to for your model to start trading so that doesn't make sense. So anyway, we uh now and on the second time interval, but I just I'm going to keep it like this just to just to show you like what what's happening, right? So again, on the the second tick, we don't have enough data to generate uh uh orders. And so let's just say that was like today at uh midnight. And then that's the next time interval. And now we're going to look at the third time interval. And and again there's not enough to to generate uh uh orders. And now if we look at the fourth orders, sorry the fourth uh 12hour interval, right? that uh if we run this now uh that the now it's generated an order. So essentially our order uh it's creat an order and it's basically essentially it's predicted that it's going long because remember this is assigned quantity. is negative. That means it's telling us to to to open a short position. But here it's saying like this is the price and we've and our account is $100, right? So that's why the the quantity is one because uh that's how much we can buy with our available uh capital. Now that's the that's so that's the order, right? And now we need like our system needs to be able so we're do going to do this manually right and ex explicitly but we would automate this but I just wanted to just to uh to understand what's happening. So now we've got orders now we actually want to execute orders and I'm just this is where we can use our exchange API. So now what we're going to do is going to create an instance of exchange. Just going to call test exchange account order. Oops. [Music] And then call market order. And we're going to pass in all the parameters here, right? So order So order signed quantity and then the price and what we're going to do here. Ah we can pass it as a decimal as well but uh yeah so now we're going to run this. So you see here that it's created a trade now. And now if we look at the exchange to see what's happened. So you see here it's created the position now and it's bought one unit and you can see we've got a trade here and it the associated P&L is zero because it hasn't closed or reduced the position. So now now we this is what we're going to do now is we're going to do this. We're now going to so let's say we now we're on the next 12hour interval and now we've got a new price. So we want to stream that new price into our strategy. And so now we stream it in and see now what happens. It's generated two orders. The first order is saying to close the position because our position at the moment is is positive one, right? And we want to close it. So, we need to send an order for for minus one. And that's going to close the position. Uh once it's closed the position, we want this other one's going to open up a new position. And you can see here that it's a negative number. So, it's now going to open a short position. And that's essentially uh short position is you're making a bet, the price is going to go down. And I just want to show you like manually what happens. Uh so for example, oops. So now what we're going to do is we're just going to do this. We're going to So that's the first order, remember, was to to close. So it's this one. We're going to run this and then to see what happens. So, we've now run it and you can see now we've got an associated profit and loss of $15 uh dollars. And now if we look at the exchange, you can see now uh positions now closed. We have no positions available. Uh, and you can see, for example, we could write this down into a CSV file to to analyze what what trees were were done. And so, but that's just one order of two. And now the next order. So, we're just now going to [Music] Can we call I should maybe just So, now we're going to call the exchange uh again. And so, this time it's going to um call market order. We can just use this Okay. So, and now it should open uh a position and you can see here it's a negative uh number. So, this represents a short position and uh you can see all our trades are accumulating and but this is just a test. So we can just accumulate the trades for now. But um it would probably be better if we wrote the all that rather than keep them in memory is to write them down to disk like it's a CSV file. And so yeah, so that's and now what we're going to do is just to show for example now if we let's say the price goes down and it's again just to show what happens. So now it's going to do the opposite, right? So that was it's it's going to give us the size so we can close the the position in full and then it's going to open a new position which is uh uh it's now going to be a long position and it's going to do exactly the the same. So we would do for example orders exchange So you see here that we've now that now the position is going to be closed. Oh, and we've got the associated P&L as well. Uh so you see the positions closed. And then for the second order, we're going to to that'll open up a new position that'll be long. So maybe if we just do that now as well. And then if I run exchange, so you now see that we have a long position of this size. And that's that concludes the the basics of the trading system. There's a lot more. Uh but I decided to cut a lot out to make the the video shorter. And so to conclude, I've shown like how to put it all together, showing how to stream prices to create the features, and show how the model makes a forecast, and how it all fits together. So showing like how the strategy generates orders that opens and closes uh positions. So, and then I think what we'll do for the next video, we're going to maybe get rid of this. For the next video, we're going to put uh it live. I'm I'm still hesitant to actually give the code to actually like send orders to a real exchange because I'm just worried that for example, someone downloads the code, changes some of the parameters, maybe the weights or even what it's actually trading, puts a lot of money, loses it, and then like uh yeah, I just want to avoid situations like that. So um I think I'll I I pretty want to make it transparent but I so what I'll do is I'll probably give all the like the code but just not the actual uh implementation of the exchange the so uh then and then what we'll do is we'll put it live with some real money and let it run and then for example if it starts to hope uh we can still learn for example if it if the performance starts to decay because this is a very important lesson this will be called like model drift but we'll only find out until we actually run it live and uh then you know for example if there is like model drift then there's something like you can do like a a sliding window approach to to training so rather than just like a traditional time split then we can just do like a uh a sliding window and then just always recalibrate our weights after a certain time anyway but we we will I will maybe run this for like a month or two months run it and then document it and then create another video. So, you won't see it uh next week or anything, but yeah, we'll see it uh lately in the the future. So, I think that concludes everything. That's um feel free to ask any questions. I I like to answer the the questions. And yeah, please like and subscribe and thank you very much.