There is no intuitive way to do this in Animation Nodes. I proposed a system to the developer that should hopefully allow us to do this intuitively. But he is still studying it. In the meantime, I will tell you how to make such system manually.
Storing Data
Each execution in Animation Nodes is independent of the next one, and thus we can't pass data between executions. To solve this, we need store the data in some place accessible by all executions at all times, a typical solution is to store the data in-memory, somewhere in the animation_nodes
or bpy
modules for instance. In python, to store some data data
in the animation_nodes
module in an attribute called test
, we can use the setattr()
built-in method as follows:
setattr(animation_nodes, "test", data)
If you are still not sure how this work, you can think of it as follows. We are storing the data data
in a place in memory called animation_nodes.test
, we can later access this data simply by getting it from the place we stored it in, that is, animation_nodes.test
. Enough about this, lets talk practicality.
Implementation
What I shall show is tracing the location of the particles in a form of splines. First, we are going to compute what is known as the initial condition, which is the initial state of the system. In our case, the initial condition is a list of empty splines. We can generate it using the Fill List Node set to Spline type, where the amount of empty splines is equal to the number of particles (make sure not to filter the particles in anyway, because we want to maintain the number of particles):
What are going to do is append the particles locations to each of those splines at each frame (execution). In an expression node, I am going to input the initial conditions and set this expression:
initial if bpy.data.scenes[0].frame_current == 1 else animation_nodes.splines
Basically, this returns initial
which is the initial condition (list of empty splines) if the frame is equal to one and animation_nodes.splines
(some data we are going to set later on) otherwise. Why did we do this step? We are merely resetting the splines to be empty (to be the initial condition) when the frames becomes one, that is, when the time line resets, and that is what we want, we want the animation to reset when the animation resets. Now, I am going to make a loop that appends the current particles positions to their corresponding splines:

And lastly, I am going to assign/reassign the data at the memory location animation_nodes.splines
to be the new data after appending using the setattr()
method we described before:

Lets recap what is happening here. At frame 1, the input to the loop are empty splines, the output of the loop is splines with a single point that has the location of the particles, this output is assigned to the memory location animation_nodes.splines
. At frame 2, the input to the loop is the data at animation_nodes.splines
, that is, the splines with a single vertex that has the location of the particles at frame 1, the output is splines that has two vertices, the first is that of locations of the particles at frame 1 and the second is that of the locations of the particles at frame 2, this new splines are assigned to animation_nodes.splines
. So, you see that at each new frame, the splines get a new point that is the location of the particle at this frame. The result is growing splines as the time passes:

The structure we just used can be edited appropriately to suite your needs, and it nearly stays the same, get data, edit it, reassign it, repeat.