Based on Edmund's answer I have written a function that will produce cross-correlation sweep. Excellent for sweeps, but not optimised for performance.

```
TSCorrelation[ts1_, ts2_] := Module[
{aligned, r, z, seZ, ZtoR, up, down, error},
aligned = Select[
GatherBy[ Normal@ts1~ Join ~ Normal@ts2, First],
Length[#] == 2 &] [[All, {1, 2}, 2]];
(*chaeck if enough data is available*)
If[Length@aligned < 3, Return[
<| "correlation" -> 0, "error" -> 1.0 ,
"error bounds" -> {1, 0}, "size" -> Length@aligned |> ]];
r = N@Correlation[ aligned[[All, 1]] , aligned[[All, 2]] ];
(* error estimate *)
z = 0.5 Log[ (1 + r)/(1 - r)];
seZ = 1/Sqrt[Length@aligned - 3];
ZtoR[zz_] := (Exp[2 zz] - 1)/(Exp[2 zz] + 1);
{up, down} = {ZtoR[z + seZ], ZtoR[z - seZ]};
error = (up - down )/2;
(* out *)
<| "correlation" -> r, "error" -> error ,
"error bounds" -> {up, down}, "size" -> Length@aligned |>
]
```

and

```
TSCrossCorrelation[ts1_, ts2_, unit_: "Day"] := Module[
{minShift, maxShift, ccRaw},
minShift = -QuantityMagnitude@
DateDifference[ts1["FirstDate"], ts2["LastDate"], unit];
maxShift =
QuantityMagnitude@
DateDifference[ts2["FirstDate"], ts1["LastDate"], unit];
ccRaw = Quiet@Table[
Append[ TSCorrelation[TimeSeriesShift[ ts1, {shift, unit}], ts2],
"shift" -> shift ],
{shift, Range @@ Sort@{minShift, maxShift}}
];
(*filter out high errors *)
Select[ ccRaw, #["error"] <= 0.3 &]
]
```

Usage example:

```
data1 = FinancialData["SBUX",
"Close", {{2013, 1, 1}, {2013, 12, 1}, "Day"}];
data2 = FinancialData["SBUX",
"Close", {{2013, 5, 1}, {2013, 6, 1}, "Day"}];
ts1 = TimeSeries[data1[[All, 2]], {data1[[1, 1]], Automatic, "Day"}];
ts2 = TimeSeries[data2[[All, 2]], {data2[[1, 1]], Automatic, "Day"}];
cc = Dataset@TSCrossCorrelation[ ts1, ts2];
ListPlot @ cc[All, {"shift", "correlation"}]
```