Since your figure is a closed loop, its parametric curves $x(t)$ and $y(t)$ must be periodic functions. This suggests one way to generate such figures, by constructing random smooth periodic functions $x(t)$ and $y(t)$ via summation of sinusoids/harmonics with randomized amplitude and phase. Unfortunately, it would be difficult to guarantee such a figure didn't self intersect.
But a nearby idea would be to switch to polar coordinates, and think about circle-like figures whose radius $r(t)$ is a function of the polar angle $t$. The closed loop condition requires that $r(t)$ is periodic, and you can use the same sort of sum-of-harmonics procedure to generate a random smooth periodic $r(t)$. If you "bias" this $r(t)$ by adding some constant term (larger than the sum of your randomized amplitudes), you'll get non-intersecting figures.
Some matlab code that implements this idea:
clear all
close all
% Randomize amplitude and phase.
H = 10;
rho = rand(1,H) .* logspace(-0.5,-2.5,H);
phi = rand(1,H) .* 2*pi;
% Accumulate r(t) over t=[0,2*pi]
t = linspace(0,2*pi,101);
r = ones(size(t));
for h=1:H
r = r + rho(h)*sin(h*t+phi(h));
end
% Reconstruct x(t), y(t)
x = r .* cos(t);
y = r .* sin(t);
% Plot r(t) vs t
figure;
plot(t,r,'r-');
xlabel('t, radians');
ylabel('r(t)');
% Plot x(t) and y(t)
figure;
hold on;
plot(0,0,'ko');
plot(cos(t),sin(t),'k--');
plot(x,y,'b-');
xlabel('x(t)');
ylabel('y(t)');
axis equal;
And here's some example (randomized) output:
It should be straightforward to implement the same idea using python + numpy + matplotlib.