The approach below fits to a rotated parabola.

I estimate the coefficients $A, B, C$ by first removing the rotation (rotate $-\theta$). Then I plug in the coefficients of a regular parabola, and finally rotate the result back.
I give curve_fit() both the $x$ and $y$ coordinates (your code only supplies $x$ to the model).
The model function rotated_parabola() does the following:
- Assume $x, y$ are in rotated space. Undo the rotation on $x$ by applying $-\theta$ to $x$.
- Now it's a regular parabola, where we estimate $A, B, C$.
- Rotate the estimated $y$ back to the original orientation by applying $\theta$.
Reproducible example
import numpy as np from scipy.optimize import curve_fit from matplotlib import pyplot as plt np.set_printoptions(suppress=True) # # Synthesise test data # It's a parabola defined by A, B, C, which is then rotated by THETA # THETA = 45 * np.pi/180 A, B, C = (1, 1, 3) #Generate the parabola defined by A, B, C data_x_parab = np.linspace(-2, 1, num=25) data_y_parab = A * data_x_parab**2 + B * data_x_parab + C #Rotate the parabola by THETA data_xy = (data_x, data_y) = ( np.row_stack([ (np.cos(THETA), -np.sin(THETA)), (np.sin(THETA), np.cos(THETA)) ]) @ np.row_stack([data_x_parab, data_y_parab]) ) def rotated_parabola(xy, theta, a, b, c): x, y = xy #First, apply -theta to reverse the rotation x_parabola = x * np.cos(-theta) - y * np.sin(-theta) # Parabola equation is now valid # Fit the parameters (a, b, c) of the parabola y_parabola = a * x_parabola**2 + b * x_parabola + c # Rotate the fitted point back into the original space y_fit = x_parabola * np.sin(theta) + y_parabola * np.cos(theta) return y_fit #Fit popt, pcov = curve_fit(rotated_parabola, data_xy, data_y) print( 'Data parameters:', THETA * 180/np.pi, A, B, C, '\n' 'Fitted parameters:', round(popt[0] * 180/np.pi), *popt[1:].round(1) ) # # Plot data # f, ax = plt.subplots(figsize=(8, 4), layout='tight') #Data ax.scatter(data_x_parab, data_y_parab, marker='s', s=12, alpha=0.1, color='black', label='parabola') ax.scatter(data_x, data_y, marker='s', s=12, color='black', label='rotated parabola') #Plot the fitted curve y_fitted = rotated_parabola(data_xy, *popt) ax.plot(data_x, y_fitted, color='tab:orange', linestyle='-', linewidth=7, alpha=0.3, label='fit') #Formatting ax.legend() ax.spines[['top', 'right']].set_visible(False) ax.set(xlabel='x', ylabel='y', title='Fitting a rotated curve using curve_fit()'); ax.set_aspect('equal')