In your query, you are retrieving data from just one table and your filter criteria are ...
equality on symbol
range scan low-to-high on timestamp.
Therefore, (as Gordon mentioned) an index on two columns (symbol, timestamp) can satisfy your query, both the filtering and the ordering, quite efficiently. The query planner will do a random access operation on the index to the correct symbol and the starting timestamp, then read the index sequentially until the ending timestamp. That's efficient.
But, your SELECT * may be holding you back on performance. Why? If you used, for example, SELECT symbol, timestamp, cusip, name then you could create a so-called covering index on (symbol, timestamp, cusip, name). In that case, the entire query would be satisfied by scanning the index. That can be very efficient indeed.
Pro tip Avoid SELECT *, both for software stability and performance reasons.
Pro tip Don't add extra indexes to a table unless you know they will help particular queries. MySQL only uses a single index for each table in a query or subquery. Neither an index on just timestamp or just symbol will help much: MySQL still has to examine a lot of rows to satisfy your filtering criteria.
trades? One way of cutting down the execution time is to only select the properties you need. In other words, writeSELECT * FROMmore specific.ORDER BYis really the thing slowing it down, ordering by all 50K rows is the bulk of the work in the querySHOW CREATE TABLE trades) and theEXPLAINresult. This is the minimum of information for SQL performance questions.