You can try to leverage union splitting. Define a union type of all possible trades and use this to declare your vector.
Here is an example:
using BenchmarkTools
N=100
struct A{T}
a::T
end
function myfill!(X)
for i=1:length(X)
if i%3==0
X[i]=A(Int16(i))
elseif i%3==1
X[i]=A(Int32(i))
elseif i%3==2
X[i]=A(Int64(i))
end
end
end
function mysum(X)
s::Int64=0
for x in X
s+=x.a
end
s
end
VA=Vector{A}(undef,N)
myfill!(VA)
@show mysum(VA)
@btime mysum(VA)
const U=Union{A{Int16}, A{Int32}, A{Int64}}
VU=Vector{U}(undef,N)
myfill!(VU)
@show mysum(VU)
@btime mysum(VU)
It gives
mysum(VA) = 5050
3.109 μs (138 allocations: 2.16 KiB)
mysum(VU) = 5050
106.416 ns (1 allocation: 16 bytes)
I wrote about union splitting here.